From 32870ad48681337e7e73a85e932a4935d9efd7e2 Mon Sep 17 00:00:00 2001 From: mndza Date: Tue, 8 Jul 2025 16:37:35 +0200 Subject: [PATCH 1/6] firmware: no division when calculating n_lo in RFFC5071 synth --- firmware/common/rffc5071.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/common/rffc5071.c b/firmware/common/rffc5071.c index ccd17b4b..f3f25c5d 100644 --- a/firmware/common/rffc5071.c +++ b/firmware/common/rffc5071.c @@ -231,10 +231,10 @@ uint64_t rffc5071_config_synth_int(rffc5071_driver_t* const drv, uint16_t lo) uint16_t p1nmsb; uint8_t p1nlsb; - /* Calculate n_lo */ + /* Calculate n_lo (no division) */ uint8_t n_lo = 0; - uint16_t x = LO_MAX / lo; - while ((x > 1) && (n_lo < 5)) { + uint16_t x = LO_MAX >> 1; + while ((x >= lo) && (n_lo < 5)) { n_lo++; x >>= 1; } From d3ee4178073b8c3b771ef74592280319da87c616 Mon Sep 17 00:00:00 2001 From: mndza Date: Wed, 9 Jul 2025 12:29:39 +0200 Subject: [PATCH 2/6] firmware: fix max283x fractional long division --- firmware/common/max2837.c | 4 ++-- firmware/common/max2839.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/common/max2837.c b/firmware/common/max2837.c index 5fdc2ea4..9d04f6f6 100644 --- a/firmware/common/max2837.c +++ b/firmware/common/max2837.c @@ -233,8 +233,8 @@ void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq) div_cmp = 30000000; for (i = 0; i < 20; i++) { div_frac <<= 1; - div_cmp >>= 1; - if (div_rem > div_cmp) { + div_rem <<= 1; + if (div_rem >= div_cmp) { div_frac |= 0x1; div_rem -= div_cmp; } diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c index 868855d4..86ab0ba9 100644 --- a/firmware/common/max2839.c +++ b/firmware/common/max2839.c @@ -239,8 +239,8 @@ void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq) div_cmp = 30000000; for (i = 0; i < 20; i++) { div_frac <<= 1; - div_cmp >>= 1; - if (div_rem > div_cmp) { + div_rem <<= 1; + if (div_rem >= div_cmp) { div_frac |= 0x1; div_rem -= div_cmp; } From ac0552a5b9a795fb10882fe61836968870edef58 Mon Sep 17 00:00:00 2001 From: mndza Date: Tue, 19 Aug 2025 11:40:08 +0200 Subject: [PATCH 3/6] firmware: optimize and rename rffc5071 synth config function --- firmware/common/rffc5071.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/firmware/common/rffc5071.c b/firmware/common/rffc5071.c index f3f25c5d..2598754b 100644 --- a/firmware/common/rffc5071.c +++ b/firmware/common/rffc5071.c @@ -220,12 +220,11 @@ void rffc5071_enable(rffc5071_driver_t* const drv) #define REF_FREQ 40 #define FREQ_ONE_MHZ (1000 * 1000) -/* configure frequency synthesizer in integer mode (lo in MHz) */ -uint64_t rffc5071_config_synth_int(rffc5071_driver_t* const drv, uint16_t lo) +/* configure frequency synthesizer (lo in MHz) */ +uint64_t rffc5071_config_synth(rffc5071_driver_t* const drv, uint16_t lo) { - uint8_t lodiv; uint16_t fvco; - uint8_t fbkdiv; + uint8_t fbkdivlog; uint16_t n; uint64_t tune_freq_hz; uint16_t p1nmsb; @@ -239,8 +238,7 @@ uint64_t rffc5071_config_synth_int(rffc5071_driver_t* const drv, uint16_t lo) x >>= 1; } - lodiv = 1 << n_lo; - fvco = lodiv * lo; + fvco = lo << n_lo; /* higher divider and charge pump current required above * 3.2GHz. Programming guide says these values (fbkdiv, n, @@ -248,26 +246,24 @@ uint64_t rffc5071_config_synth_int(rffc5071_driver_t* const drv, uint16_t lo) * improve phase noise, since the VCO will already be stable * and will be unaffected. */ if (fvco > 3200) { - fbkdiv = 4; + fbkdivlog = 2; set_RFFC5071_PLLCPL(drv, 3); } else { - fbkdiv = 2; + fbkdivlog = 1; set_RFFC5071_PLLCPL(drv, 2); } - uint64_t tmp_n = ((uint64_t) fvco << 29ULL) / (fbkdiv * REF_FREQ); - n = tmp_n >> 29ULL; + uint64_t tmp_n = ((uint64_t) fvco << (24ULL - fbkdivlog)) / REF_FREQ; + n = tmp_n >> 24ULL; + p1nmsb = (tmp_n >> 8ULL) & 0xffff; + p1nlsb = tmp_n & 0xff; - p1nmsb = (tmp_n >> 13ULL) & 0xffff; - p1nlsb = (tmp_n >> 5ULL) & 0xff; - - tune_freq_hz = (REF_FREQ * (tmp_n >> 5ULL) * fbkdiv * FREQ_ONE_MHZ) / - (lodiv * (1 << 24ULL)); + tune_freq_hz = (tmp_n * REF_FREQ * FREQ_ONE_MHZ) >> (24 - fbkdivlog + n_lo); /* Path 2 */ set_RFFC5071_P2LODIV(drv, n_lo); set_RFFC5071_P2N(drv, n); - set_RFFC5071_P2PRESC(drv, fbkdiv >> 1); + set_RFFC5071_P2PRESC(drv, fbkdivlog); set_RFFC5071_P2NMSB(drv, p1nmsb); set_RFFC5071_P2NLSB(drv, p1nlsb); @@ -282,7 +278,7 @@ uint64_t rffc5071_set_frequency(rffc5071_driver_t* const drv, uint16_t mhz) uint32_t tune_freq; rffc5071_disable(drv); - tune_freq = rffc5071_config_synth_int(drv, mhz); + tune_freq = rffc5071_config_synth(drv, mhz); rffc5071_enable(drv); return tune_freq; From 2e6bb0ab6856d6168db07ad53ed41f42118133c2 Mon Sep 17 00:00:00 2001 From: mndza Date: Fri, 11 Jul 2025 12:29:11 +0200 Subject: [PATCH 4/6] firmware: rffc5071 synth configuration accepts Hz instead of MHz --- firmware/common/mixer.c | 6 +++--- firmware/common/mixer.h | 4 ++-- firmware/common/rffc5071.c | 25 ++++++++++++------------- firmware/common/rffc5071.h | 4 ++-- firmware/common/tuning.c | 17 +++++++---------- 5 files changed, 26 insertions(+), 30 deletions(-) diff --git a/firmware/common/mixer.c b/firmware/common/mixer.c index 9aa556bf..e2747317 100644 --- a/firmware/common/mixer.c +++ b/firmware/common/mixer.c @@ -95,13 +95,13 @@ void mixer_setup(mixer_driver_t* const mixer) #endif } -uint64_t mixer_set_frequency(mixer_driver_t* const mixer, uint16_t mhz) +uint64_t mixer_set_frequency(mixer_driver_t* const mixer, uint64_t hz) { #if (defined JAWBREAKER || defined HACKRF_ONE) - return rffc5071_set_frequency(mixer, mhz); + return rffc5071_set_frequency(mixer, hz); #endif #ifdef RAD1O - return max2871_set_frequency(mixer, mhz); + return max2871_set_frequency(mixer, hz / 1000000); #endif } diff --git a/firmware/common/mixer.h b/firmware/common/mixer.h index fd7203c7..c882e898 100644 --- a/firmware/common/mixer.h +++ b/firmware/common/mixer.h @@ -37,8 +37,8 @@ typedef max2871_driver_t mixer_driver_t; extern void mixer_bus_setup(mixer_driver_t* const mixer); extern void mixer_setup(mixer_driver_t* const mixer); -/* Set frequency (MHz). */ -extern uint64_t mixer_set_frequency(mixer_driver_t* const mixer, uint16_t mhz); +/* Set frequency (Hz). */ +extern uint64_t mixer_set_frequency(mixer_driver_t* const mixer, uint64_t hz); /* Set up rx only, tx only, or full duplex. Chip should be disabled * before _tx, _rx, or _rxtx are called. */ diff --git a/firmware/common/rffc5071.c b/firmware/common/rffc5071.c index 2598754b..09686ee6 100644 --- a/firmware/common/rffc5071.c +++ b/firmware/common/rffc5071.c @@ -216,14 +216,14 @@ void rffc5071_enable(rffc5071_driver_t* const drv) rffc5071_regs_commit(drv); } -#define LO_MAX 5400 -#define REF_FREQ 40 -#define FREQ_ONE_MHZ (1000 * 1000) +#define FREQ_ONE_MHZ (1000ULL * 1000ULL) +#define REF_FREQ (40 * FREQ_ONE_MHZ) +#define LO_MAX (5400 * FREQ_ONE_MHZ) -/* configure frequency synthesizer (lo in MHz) */ -uint64_t rffc5071_config_synth(rffc5071_driver_t* const drv, uint16_t lo) +/* configure frequency synthesizer (lo in Hz) */ +uint64_t rffc5071_config_synth(rffc5071_driver_t* const drv, uint64_t lo) { - uint16_t fvco; + uint64_t fvco; uint8_t fbkdivlog; uint16_t n; uint64_t tune_freq_hz; @@ -232,7 +232,7 @@ uint64_t rffc5071_config_synth(rffc5071_driver_t* const drv, uint16_t lo) /* Calculate n_lo (no division) */ uint8_t n_lo = 0; - uint16_t x = LO_MAX >> 1; + uint64_t x = LO_MAX >> 1; while ((x >= lo) && (n_lo < 5)) { n_lo++; x >>= 1; @@ -245,7 +245,7 @@ uint64_t rffc5071_config_synth(rffc5071_driver_t* const drv, uint16_t lo) * maybe pump?) can be changed back after enable in order to * improve phase noise, since the VCO will already be stable * and will be unaffected. */ - if (fvco > 3200) { + if (fvco > (3200 * FREQ_ONE_MHZ)) { fbkdivlog = 2; set_RFFC5071_PLLCPL(drv, 3); } else { @@ -253,12 +253,12 @@ uint64_t rffc5071_config_synth(rffc5071_driver_t* const drv, uint16_t lo) set_RFFC5071_PLLCPL(drv, 2); } - uint64_t tmp_n = ((uint64_t) fvco << (24ULL - fbkdivlog)) / REF_FREQ; + uint64_t tmp_n = (fvco << (24ULL - fbkdivlog)) / REF_FREQ; n = tmp_n >> 24ULL; p1nmsb = (tmp_n >> 8ULL) & 0xffff; p1nlsb = tmp_n & 0xff; - tune_freq_hz = (tmp_n * REF_FREQ * FREQ_ONE_MHZ) >> (24 - fbkdivlog + n_lo); + tune_freq_hz = (tmp_n * REF_FREQ) >> (24 - fbkdivlog + n_lo); /* Path 2 */ set_RFFC5071_P2LODIV(drv, n_lo); @@ -272,13 +272,12 @@ uint64_t rffc5071_config_synth(rffc5071_driver_t* const drv, uint16_t lo) return tune_freq_hz; } -/* !!!!!!!!!!! hz is currently ignored !!!!!!!!!!! */ -uint64_t rffc5071_set_frequency(rffc5071_driver_t* const drv, uint16_t mhz) +uint64_t rffc5071_set_frequency(rffc5071_driver_t* const drv, uint64_t hz) { uint32_t tune_freq; rffc5071_disable(drv); - tune_freq = rffc5071_config_synth(drv, mhz); + tune_freq = rffc5071_config_synth(drv, hz); rffc5071_enable(drv); return tune_freq; diff --git a/firmware/common/rffc5071.h b/firmware/common/rffc5071.h index aa30183f..94904245 100644 --- a/firmware/common/rffc5071.h +++ b/firmware/common/rffc5071.h @@ -55,8 +55,8 @@ extern void rffc5071_reg_write(rffc5071_driver_t* const drv, uint8_t r, uint16_t * provided routines for those operations. */ extern void rffc5071_regs_commit(rffc5071_driver_t* const drv); -/* Set frequency (MHz). */ -extern uint64_t rffc5071_set_frequency(rffc5071_driver_t* const drv, uint16_t mhz); +/* Set frequency (Hz). */ +extern uint64_t rffc5071_set_frequency(rffc5071_driver_t* const drv, uint64_t hz); /* Set up rx only, tx only, or full duplex. Chip should be disabled * before _tx, _rx, or _rxtx are called. */ diff --git a/firmware/common/tuning.c b/firmware/common/tuning.c index 120831c4..08432ad9 100644 --- a/firmware/common/tuning.c +++ b/firmware/common/tuning.c @@ -61,12 +61,10 @@ uint64_t freq_cache = 100000000; bool set_freq(const uint64_t freq) { bool success; - uint32_t mixer_freq_mhz; - uint32_t MAX2837_freq_hz; + uint64_t mixer_freq_hz; uint64_t real_mixer_freq_hz; const uint32_t freq_mhz = freq / FREQ_ONE_MHZ; - const uint32_t freq_hz = freq % FREQ_ONE_MHZ; success = true; @@ -80,16 +78,15 @@ bool set_freq(const uint64_t freq) /* IF is graduated from 2650 MHz to 2340 MHz */ max2837_freq_nominal_hz = (2650 * FREQ_ONE_MHZ) - (freq / 7); #endif - mixer_freq_mhz = (max2837_freq_nominal_hz / FREQ_ONE_MHZ) + freq_mhz; + mixer_freq_hz = max2837_freq_nominal_hz + freq; /* Set Freq and read real freq */ - real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz); + real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_hz); max283x_set_frequency(&max283x, real_mixer_freq_hz - freq); sgpio_cpld_set_mixer_invert(&sgpio_config, 1); } else if ((freq_mhz >= MIN_BYPASS_FREQ_MHZ) && (freq_mhz < MAX_BYPASS_FREQ_MHZ)) { rf_path_set_filter(&rf_path, RF_PATH_FILTER_BYPASS); - MAX2837_freq_hz = (freq_mhz * FREQ_ONE_MHZ) + freq_hz; /* mixer_freq_mhz <= not used in Bypass mode */ - max283x_set_frequency(&max283x, MAX2837_freq_hz); + max283x_set_frequency(&max283x, freq); sgpio_cpld_set_mixer_invert(&sgpio_config, 0); } else if ((freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz <= MAX_HP_FREQ_MHZ)) { if (freq_mhz < MID1_HP_FREQ_MHZ) { @@ -107,9 +104,9 @@ bool set_freq(const uint64_t freq) ((freq - (MID2_HP_FREQ_MHZ * FREQ_ONE_MHZ)) / 9); } rf_path_set_filter(&rf_path, RF_PATH_FILTER_HIGH_PASS); - mixer_freq_mhz = freq_mhz - (max2837_freq_nominal_hz / FREQ_ONE_MHZ); + mixer_freq_hz = freq - max2837_freq_nominal_hz; /* Set Freq and read real freq */ - real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz); + real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_hz); max283x_set_frequency(&max283x, freq - real_mixer_freq_hz); sgpio_cpld_set_mixer_invert(&sgpio_config, 0); } else { @@ -154,7 +151,7 @@ bool set_freq_explicit( sgpio_cpld_set_mixer_invert(&sgpio_config, 0); } if (path != RF_PATH_FILTER_BYPASS) { - (void) mixer_set_frequency(&mixer, lo_freq_hz / FREQ_ONE_MHZ); + (void) mixer_set_frequency(&mixer, lo_freq_hz); } return true; } From 5520f8467c3310a5cb2bd61cac3c89cf783850c8 Mon Sep 17 00:00:00 2001 From: mndza Date: Tue, 19 Aug 2025 11:27:16 +0200 Subject: [PATCH 5/6] firmware: round to nearest frequency when tuning --- firmware/common/max2837.c | 1 + firmware/common/max2839.c | 1 + firmware/common/rffc5071.c | 5 ++++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/firmware/common/max2837.c b/firmware/common/max2837.c index 9d04f6f6..46da787d 100644 --- a/firmware/common/max2837.c +++ b/firmware/common/max2837.c @@ -227,6 +227,7 @@ void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq) } /* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */ + freq += (30000000 >> 21); /* round to nearest frequency */ div_int = freq / 30000000; div_rem = freq % 30000000; div_frac = 0; diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c index 86ab0ba9..bd49b924 100644 --- a/firmware/common/max2839.c +++ b/firmware/common/max2839.c @@ -233,6 +233,7 @@ void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq) } /* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */ + freq += (30000000 >> 21); /* round to nearest frequency */ div_int = freq / 30000000; div_rem = freq % 30000000; div_frac = 0; diff --git a/firmware/common/rffc5071.c b/firmware/common/rffc5071.c index 09686ee6..3156e6ea 100644 --- a/firmware/common/rffc5071.c +++ b/firmware/common/rffc5071.c @@ -253,7 +253,10 @@ uint64_t rffc5071_config_synth(rffc5071_driver_t* const drv, uint64_t lo) set_RFFC5071_PLLCPL(drv, 2); } - uint64_t tmp_n = (fvco << (24ULL - fbkdivlog)) / REF_FREQ; + uint64_t numerator = fvco << (24ULL - fbkdivlog); + numerator += REF_FREQ / 2; /* round to nearest frequency */ + uint64_t tmp_n = numerator / REF_FREQ; + n = tmp_n >> 24ULL; p1nmsb = (tmp_n >> 8ULL) & 0xffff; p1nlsb = tmp_n & 0xff; From cae8060d0d848a13f4cde1b602a27e819e5e12cd Mon Sep 17 00:00:00 2001 From: mndza Date: Thu, 21 Aug 2025 10:01:26 +0200 Subject: [PATCH 6/6] firmware: disable rffc5071 dithering, tune to nearest 625000 Hz step --- firmware/common/rffc5071.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/firmware/common/rffc5071.c b/firmware/common/rffc5071.c index 3156e6ea..ec69eed8 100644 --- a/firmware/common/rffc5071.c +++ b/firmware/common/rffc5071.c @@ -58,7 +58,7 @@ static const uint16_t rffc5071_regs_default[RFFC5071_NUM_REGS] = { 0x1e84, /* 0F */ 0x89d8, /* 10 */ 0x9d00, /* 11 */ - 0x2a20, /* 12 */ + 0x3a20, /* 12, dithering off */ 0x0000, /* 13 */ 0x0000, /* 14 */ 0x0000, /* 15 */ @@ -100,16 +100,7 @@ void rffc5071_setup(rffc5071_driver_t* const drv) set_RFFC5071_P2LODIV(drv, 0); set_RFFC5071_P2PRESC(drv, 0); set_RFFC5071_P2VCOSEL(drv, 0); - - set_RFFC5071_P2N(drv, 0); - set_RFFC5071_P2LODIV(drv, 0); - set_RFFC5071_P2PRESC(drv, 0); - set_RFFC5071_P2VCOSEL(drv, 0); - - set_RFFC5071_P2N(drv, 0); - set_RFFC5071_P2LODIV(drv, 0); - set_RFFC5071_P2PRESC(drv, 0); - set_RFFC5071_P2VCOSEL(drv, 0); + set_RFFC5071_P2NLSB(drv, 0); /* set ENBL and MODE to be configured via 3-wire interface, * not control pins. */ @@ -253,9 +244,13 @@ uint64_t rffc5071_config_synth(rffc5071_driver_t* const drv, uint64_t lo) set_RFFC5071_PLLCPL(drv, 2); } - uint64_t numerator = fvco << (24ULL - fbkdivlog); - numerator += REF_FREQ / 2; /* round to nearest frequency */ - uint64_t tmp_n = numerator / REF_FREQ; + uint64_t tmp_n = (fvco << (24ULL - fbkdivlog)) / REF_FREQ; + + /* Round to nearest step = ref_MHz / 2**s. For s=6, step=625000 Hz */ + /* This also ensures the lowest 22-s fractional bits are set to 0. */ + const uint8_t s = 6; + const uint8_t d = (24 - fbkdivlog + n_lo) - s; + tmp_n = ((tmp_n + (1 << (d - 1))) >> d) << d; n = tmp_n >> 24ULL; p1nmsb = (tmp_n >> 8ULL) & 0xffff; @@ -268,7 +263,10 @@ uint64_t rffc5071_config_synth(rffc5071_driver_t* const drv, uint64_t lo) set_RFFC5071_P2N(drv, n); set_RFFC5071_P2PRESC(drv, fbkdivlog); set_RFFC5071_P2NMSB(drv, p1nmsb); - set_RFFC5071_P2NLSB(drv, p1nlsb); + if (s > 14) { + /* Only set when the step size is small enough. */ + set_RFFC5071_P2NLSB(drv, p1nlsb); + } rffc5071_regs_commit(drv);