From 7b3b28f8afe477f19fffefa29adf540d18fd9e1b Mon Sep 17 00:00:00 2001 From: TT Date: Sat, 10 Sep 2016 18:24:44 +0900 Subject: [PATCH] add gain/offset/power command, clean up si5351a control --- main.c | 16 ++++++- nanovna.h | 2 +- si5351.c | 139 ++++++++++++++++++++++++------------------------------ si5351.h | 11 +++-- 4 files changed, 84 insertions(+), 84 deletions(-) diff --git a/main.c b/main.c index 177ffb5..15df6fa 100644 --- a/main.c +++ b/main.c @@ -72,6 +72,7 @@ static void cmd_reset(BaseSequentialStream *chp, int argc, char *argv[]) int32_t frequency_offset = 5000; int32_t frequency = 10000000; +uint8_t drive_strength = SI5351_CLK_DRIVE_STRENGTH_2MA; void set_frequency(int freq) { @@ -80,7 +81,7 @@ void set_frequency(int freq) si5351_set_frequency(0, freq + frequency_offset); si5351_set_frequency(1, freq); #else - si5351_set_frequency_with_offset(freq, frequency_offset); + si5351_set_frequency_with_offset(freq, frequency_offset, drive_strength); #endif } @@ -106,6 +107,18 @@ static void cmd_freq(BaseSequentialStream *chp, int argc, char *argv[]) set_frequency(freq); } +static void cmd_power(BaseSequentialStream *chp, int argc, char *argv[]) +{ + if (argc != 1) { + chprintf(chp, "usage: power {0-3}\r\n"); + return; + } + drive_strength = atoi(argv[0]); + set_frequency(frequency); +} + + + static void cmd_time(BaseSequentialStream *chp, int argc, char *argv[]) { (void)argc; @@ -304,6 +317,7 @@ static const ShellCommand commands[] = { "port", cmd_port }, { "stat", cmd_stat }, { "gain", cmd_gain }, + { "power", cmd_power }, { NULL, NULL } }; diff --git a/nanovna.h b/nanovna.h index c9b2639..a7308ba 100644 --- a/nanovna.h +++ b/nanovna.h @@ -33,4 +33,4 @@ extern int16_t buffer_q[]; void dsp_process(int16_t *src, int16_t *dst, size_t len); void set_agc_mode(int agcmode); -void si5351_set_frequency_with_offset(int freq, int offset); +void si5351_set_frequency_with_offset(int freq, int offset, uint8_t drive_strength); diff --git a/si5351.c b/si5351.c index 3a09c2d..4ad7127 100644 --- a/si5351.c +++ b/si5351.c @@ -130,7 +130,8 @@ si5351_setupMultisynth(uint8_t output, uint8_t pllSource, uint32_t div, // 4,6,8, 8+ ~ 900 uint32_t num, - uint32_t denom) + uint32_t denom, + uint8_t drive_strength) { /* Get the appropriate starting point for the PLL registers */ const uint8_t msreg_base[] = { @@ -149,6 +150,7 @@ si5351_setupMultisynth(uint8_t output, 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 @@ -160,19 +162,18 @@ si5351_setupMultisynth(uint8_t output, * P3[19:0] = c */ /* Set the main PLL config registers */ - if (num == 0) - { + 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 - { + } else { /* Fractional mode */ - //P1 = (uint32_t)(128 * div + floor(128 * ((float)num/(float)denom)) - 512); P1 = 128 * div + ((128 * num) / denom) - 512; - //P2 = (uint32_t)(128 * num - denom * floor(128 * ((float)num/(float)denom))); P2 = 128 * num - denom * ((128 * num) / denom); P3 = denom; } @@ -180,7 +181,7 @@ si5351_setupMultisynth(uint8_t output, /* Set the MSx config registers */ si5351_write(baseaddr, (P3 & 0x0000FF00) >> 8); si5351_write(baseaddr+1, (P3 & 0x000000FF)); - si5351_write(baseaddr+2, (P1 & 0x00030000) >> 16); /* ToDo: Add DIVBY4 (>150MHz) and R0 support (<500kHz) later */ + si5351_write(baseaddr+2, ((P1 & 0x00030000) >> 16) | div4); si5351_write(baseaddr+3, (P1 & 0x0000FF00) >> 8); si5351_write(baseaddr+4, (P1 & 0x000000FF)); si5351_write(baseaddr+5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16)); @@ -188,7 +189,7 @@ si5351_setupMultisynth(uint8_t output, si5351_write(baseaddr+7, (P2 & 0x000000FF)); /* Configure the clk control and enable the output */ - dat = SI5351_CLK_DRIVE_STRENGTH_2MA | SI5351_CLK_INPUT_MULTISYNTH_N; + dat = drive_strength | SI5351_CLK_INPUT_MULTISYNTH_N; if (pllSource == SI5351_PLL_B) dat |= SI5351_CLK_PLL_SELECT_B; if (num == 0) @@ -196,86 +197,64 @@ si5351_setupMultisynth(uint8_t output, si5351_write(clkctrl[output], dat); } -void -si5351_setupMultisynthDivBy4(uint8_t output, - uint8_t pllSource) +static uint32_t +gcd(uint32_t x, uint32_t y) { - /* Get the appropriate starting point for the PLL registers */ - const uint8_t msreg_base[] = { - SI5351_REG_42_MULTISYNTH0, - SI5351_REG_50_MULTISYNTH1, - SI5351_REG_58_MULTISYNTH2, - }; - uint8_t baseaddr = msreg_base[output]; - const uint8_t clkctrl[] = { - SI5351_REG_16_CLK0_CONTROL, - SI5351_REG_17_CLK1_CONTROL, - SI5351_REG_18_CLK2_CONTROL - }; - uint8_t dat; - - /* Set the MSx config registers */ - si5351_write(baseaddr, 0); - si5351_write(baseaddr+1, 1); - si5351_write(baseaddr+2, SI5351_DIVBY4); - si5351_write(baseaddr+3, 0); - si5351_write(baseaddr+4, 0); - si5351_write(baseaddr+5, 0); - si5351_write(baseaddr+6, 0); - si5351_write(baseaddr+7, 0); - - /* Configure the clk control and enable the output */ - dat = SI5351_CLK_DRIVE_STRENGTH_2MA - | SI5351_CLK_INPUT_MULTISYNTH_N - | SI5351_CLK_INTEGER_MODE; - if (pllSource == SI5351_PLL_B) - dat |= SI5351_CLK_PLL_SELECT_B; - si5351_write(clkctrl[output], dat); + uint32_t z; + while (y != 0) { + z = x % y; + x = y; + y = z; + } + return x; } - #define XTALFREQ 26000000L #define PLL_N 32 #define PLLFREQ (XTALFREQ * PLL_N) void -si5351_set_frequency_fixedpll(int channel, int pll, int pllfreq, int freq) +si5351_set_frequency_fixedpll(int channel, int pll, int pllfreq, int freq, + uint8_t drive_strength) { int32_t div = pllfreq / freq; // range: 8 ~ 1800 int32_t num = pllfreq - freq * div; int32_t denom = freq; - int32_t k = freq / (1<<20) + 1; + //int32_t k = freq / (1<<20) + 1; + int32_t k = gcd(num, denom); num /= k; denom /= k; - si5351_setupMultisynth(channel, pll, div, num, denom); + while (denom >= (1<<20)) { + num >>= 1; + denom >>= 1; + } + si5351_setupMultisynth(channel, pll, div, num, denom, drive_strength); } void -si5351_set_frequency_fixeddiv(int channel, int pll, int freq, int div) +si5351_set_frequency_fixeddiv(int channel, int pll, int freq, int div, + uint8_t drive_strength) { int32_t pllfreq = freq * div; int32_t multi = pllfreq / XTALFREQ; int32_t num = pllfreq - multi * XTALFREQ; +#if 0 //int32_t denom = 1000000; int32_t denom = 520000; int32_t k = XTALFREQ / denom; num /= k; - si5351_setupPLL(pll, multi, num, denom); - si5351_setupMultisynth(channel, pll, div, 0, 1); -} - -void -si5351_set_frequency_fixeddiv4(int channel, int pll, int freq) -{ - int32_t pllfreq = freq * 4; - int32_t multi = pllfreq / XTALFREQ; - int32_t num = pllfreq - multi * XTALFREQ; - //int32_t denom = 1000000; - int32_t denom = 520000; - int32_t k = XTALFREQ / denom; +#else + int32_t denom = XTALFREQ; + int32_t k = gcd(num, denom); num /= k; + denom /= k; + while (denom >= (1<<20)) { + num >>= 1; + denom >>= 1; + } +#endif si5351_setupPLL(pll, multi, num, denom); - si5351_setupMultisynthDivBy4(channel, pll); + si5351_setupMultisynth(channel, pll, div, 0, 1, drive_strength); } /* @@ -284,14 +263,14 @@ si5351_set_frequency_fixeddiv4(int channel, int pll, int freq) * 150~200MHz fractional PLL 600-900MHz, fixed divider 4 */ void -si5351_set_frequency(int channel, int freq) +si5351_set_frequency(int channel, int freq, uint8_t drive_strength) { if (freq <= 100000000) { - si5351_set_frequency_fixedpll(channel, SI5351_PLL_B, PLLFREQ, freq); + si5351_set_frequency_fixedpll(channel, SI5351_PLL_B, PLLFREQ, freq, drive_strength); } else if (freq < 150000000) { - si5351_set_frequency_fixeddiv(channel, SI5351_PLL_B, freq, 6); + si5351_set_frequency_fixeddiv(channel, SI5351_PLL_B, freq, 6, drive_strength); } else { - si5351_set_frequency_fixeddiv4(channel, SI5351_PLL_B, freq); + si5351_set_frequency_fixeddiv(channel, SI5351_PLL_B, freq, 4, drive_strength); } } @@ -303,25 +282,31 @@ si5351_set_frequency(int channel, int freq) */ #define CLK2_FREQUENCY 8000000L void -si5351_set_frequency_with_offset(int freq, int offset) +si5351_set_frequency_with_offset(int freq, int offset, uint8_t drive_strength) { si5351_disable_output(); if (freq <= 100000000) { // fractional divider mode. only PLL A is used. si5351_setupPLL(SI5351_PLL_A, 32, 0, 1); - si5351_set_frequency_fixedpll(0, SI5351_PLL_A, PLLFREQ, freq + offset); - si5351_set_frequency_fixedpll(1, SI5351_PLL_A, PLLFREQ, freq); - si5351_set_frequency_fixedpll(2, SI5351_PLL_A, PLLFREQ, CLK2_FREQUENCY); + si5351_set_frequency_fixedpll(0, SI5351_PLL_A, PLLFREQ, freq + offset, + SI5351_CLK_DRIVE_STRENGTH_2MA); + si5351_set_frequency_fixedpll(1, SI5351_PLL_A, PLLFREQ, freq, drive_strength); + si5351_set_frequency_fixedpll(2, SI5351_PLL_A, PLLFREQ, CLK2_FREQUENCY, + SI5351_CLK_DRIVE_STRENGTH_2MA); } else if (freq < 150000000) { // div by 6 mode. both PLL A and B are dedicated for CLK0, CLK1 - si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, freq + offset, 6); - si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6); - si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq * 6, CLK2_FREQUENCY); + si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, freq + offset, 6, + SI5351_CLK_DRIVE_STRENGTH_2MA); + si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength); + si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq * 6, CLK2_FREQUENCY, + SI5351_CLK_DRIVE_STRENGTH_2MA); } else { // div by 4 mode. both PLL A and B are dedicated for CLK0, CLK1 - si5351_set_frequency_fixeddiv4(0, SI5351_PLL_A, freq + offset); - si5351_set_frequency_fixeddiv4(1, SI5351_PLL_B, freq); - si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq * 4, CLK2_FREQUENCY); + si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, freq + offset, 4, + SI5351_CLK_DRIVE_STRENGTH_2MA); + si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 4, drive_strength); + si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq * 4, CLK2_FREQUENCY, + SI5351_CLK_DRIVE_STRENGTH_2MA); } si5351_reset_pll(); si5351_enable_output(); diff --git a/si5351.h b/si5351.h index 9e14ecb..a5803f3 100644 --- a/si5351.h +++ b/si5351.h @@ -60,9 +60,10 @@ void si5351_setupPLL(uint8_t pll, /* SI5351_PLL_A or SI5351_PLL_B */ uint32_t num, uint32_t denom); void si5351_setupMultisynth(uint8_t output, - uint8_t pllSource, - uint32_t div, - uint32_t num, - uint32_t denom); + uint8_t pllSource, + uint32_t div, + uint32_t num, + uint32_t denom, + uint8_t drive_strength); -void si5351_set_frequency(int channel, int freq); +void si5351_set_frequency(int channel, int freq, uint8_t drive_strength);