From 4f9c9aad7315a6cead3ae8ec71e2c4d17f769c2f Mon Sep 17 00:00:00 2001 From: erikkaashoek Date: Tue, 19 Jan 2021 12:00:28 +0100 Subject: [PATCH] First step of adding harmonic mixing and maxFreq now 4.29GHz --- main.c | 6 +- nanovna.h | 17 +++++- sa_core.c | 169 +++++++++++++++++++++++++++--------------------------- si4432.c | 7 ++- ui.c | 4 +- ui_sa.c | 31 +++++----- 6 files changed, 127 insertions(+), 107 deletions(-) diff --git a/main.c b/main.c index 500d5d2..d0057d9 100644 --- a/main.c +++ b/main.c @@ -887,7 +887,7 @@ config_t config = { #ifdef TINYSA4 .frequency_IF1 = DEFAULT_IF, .frequency_IF2 = 0, - .lpf_switch = 600000000, + .ultra_threshold = 600000000, #endif .low_level_offset = 100, // Uncalibrated .high_level_offset = 100, // Uncalibrated @@ -896,8 +896,8 @@ config_t config = { .correction_value = { +6.0, +2.8, +1.6, -0.4, 0.0, -0.4, +0.4, +3.0, +4.0, +8.1 }, #endif #ifdef TINYSA4 - .correction_frequency = { 10000, 100000, 200000, 500000, 50000000, 140000000, 200000000, 300000000, 330000000, 350000000 }, - .correction_value = { 0, 0, 0, 0, 0.0, 0, 0, 0, 0, 0 }, + .correction_frequency = { 10000, 100000, 200000, 500000, 1000000000U, 1500000000U, 2500000000U, 2800000000U, 3000000000U, 3300000000U }, + .correction_value = { 0, 0, 0, 0, 0.0, 1.5, 3, 6, 10, 10 }, #endif .setting_frequency_10mhz = 10000000, .cor_am = -14, diff --git a/nanovna.h b/nanovna.h index 78a16da..5ba9a6c 100644 --- a/nanovna.h +++ b/nanovna.h @@ -52,6 +52,8 @@ //#define __ULTRA__ // Add harmonics mode on low input. #define __SPUR__ // Does spur reduction by shifting IF //#define __USE_SERIAL_CONSOLE__ // Enable serial I/O connection (need enable HAL_USE_SERIAL as TRUE in halconf.h) +#define __HARMONIC__ + #define __QUASI_PEAK__ @@ -208,12 +210,23 @@ extern const char *info_about[]; // ------------------------------- sa_core.c ---------------------------------- +#ifdef TINYSA4 +#define SI_DRIVE_STEP 0.5 // Power step per step in drive level +#define SWITCH_ATTENUATION 34 +#define POWER_OFFSET -18 // Max level with all enabled +#define MAX_DRIVE 16 +#define MIN_DRIVE 8 +#else +#define SI_DRIVE_STEP 3 +#define SWITCH_ATTENUATION 30 +#define POWER_OFFSET 15 +#endif + extern const char * const unit_string[]; extern uint8_t signal_is_AM; extern const int reffer_freq[]; extern uint32_t minFreq; extern uint32_t maxFreq; -extern uint32_t lpf_switch; int level_is_calibrated(void); void reset_settings(int); void update_min_max_freq(void); @@ -534,7 +547,7 @@ typedef struct config { #ifdef TINYSA4 uint32_t frequency_IF1; uint32_t frequency_IF2; - uint32_t lpf_switch; + uint32_t ultra_threshold; #endif int8_t _mode; int8_t cor_am; diff --git a/sa_core.c b/sa_core.c index 6ebbe49..a29c445 100644 --- a/sa_core.c +++ b/sa_core.c @@ -60,7 +60,7 @@ void update_min_max_freq(void) case M_LOW: minFreq = 0; if (config.ultra) - maxFreq = 3300000000; + maxFreq = 4290000000; else maxFreq = 850000000; break; @@ -101,7 +101,11 @@ void reset_settings(int m) setting.unit = U_DBM; set_scale(10); set_reflevel(-10); - setting.attenuate_x2 = 0; + setting.attenuate_x2 = 0; // These should be initialized consistently + setting.level_sweep = 0.0; // And this + setting.rx_drive=MAX_DRIVE; // And this + setting.atten_step = 0; // And this, only used in low output mode + setting.level = POWER_OFFSET; // This is the level with above settings. setting.rbw_x10 = 0; setting.average = 0; setting.harmonic = 0; @@ -110,8 +114,6 @@ void reset_settings(int m) setting.subtract_stored = 0; setting.normalize_level = 0.0; setting.lo_drive=1; - setting.rx_drive=13; - setting.atten_step = 0; // Only used in low output mode setting.agc = S_AUTO_ON; setting.lna = S_AUTO_OFF; setting.tracking = false; @@ -137,8 +139,6 @@ void reset_settings(int m) setting.trigger_direction = T_UP; setting.trigger_mode = T_MID; setting.fast_speedup = 0; - setting.level_sweep = 0.0; - setting.level = -15.0; setting.trigger_level = -150.0; setting.linearity_step = 0; // setting.R = 0; // Automatic setting of R @@ -183,7 +183,7 @@ void reset_settings(int m) break; #endif case M_GENLOW: - setting.rx_drive=13; + setting.rx_drive=MAX_DRIVE; setting.lo_drive=1; set_sweep_frequency(ST_CENTER, 10000000); set_sweep_frequency(ST_SPAN, 0); @@ -489,19 +489,8 @@ void set_modulo(uint32_t f) #endif #define POWER_STEP 0 // Should be 5 dB but apparently it is lower -#define POWER_OFFSET 15 #define RECEIVE_SWITCH_ATTENUATION 21 -#ifdef TINYSA4 -#define SI_DRIVE_STEP 4 -#define SWITCH_ATTENUATION 34 -#else -#define SI_DRIVE_STEP 3 -#define SWITCH_ATTENUATION 30 -#endif - - - void set_auto_attenuation(void) { setting.auto_attenuation = true; @@ -525,9 +514,9 @@ float get_attenuation(void) float actual_attenuation = setting.attenuate_x2 / 2.0; if (setting.mode == M_GENLOW) { if (setting.atten_step) - return ( -(POWER_OFFSET + actual_attenuation - (setting.atten_step-1)*POWER_STEP + SWITCH_ATTENUATION)); + return (float)( POWER_OFFSET - actual_attenuation - (MAX_DRIVE - setting.rx_drive) * SI_DRIVE_STEP - SWITCH_ATTENUATION); else - return ( -POWER_OFFSET - actual_attenuation + (setting.rx_drive & 7) * SI_DRIVE_STEP); + return (float)( POWER_OFFSET - actual_attenuation - (MAX_DRIVE - setting.rx_drive) * SI_DRIVE_STEP); } else if (setting.atten_step) { if (setting.mode == M_LOW) return actual_attenuation + RECEIVE_SWITCH_ATTENUATION; @@ -552,7 +541,7 @@ static const int drive_dBm [16] = {-38,-35,-33,-30,-27,-24,-21,-19,-7,-4,-2, 1, void set_level(float v) // Set the output level in dB in high/low output { if (setting.mode == M_GENHIGH) { - int d = 0; +// int d = 0; // while (drive_dBm[d] < v - 1 && d < 16) // d++; // if (d == 8 && v < -12) // Round towards closest level @@ -568,25 +557,19 @@ void set_level(float v) // Set the output level in dB in high/low output void set_attenuation(float a) // Is used both in low output mode and high/low input mode { if (setting.mode == M_GENLOW) { - a = a + POWER_OFFSET; - if (a > 2*SI_DRIVE_STEP) { // +9dB - setting.rx_drive = 11; // Maximum save drive for SAW filters. - a = a - 3*SI_DRIVE_STEP; - } else if (a > SI_DRIVE_STEP) { // +6dB - setting.rx_drive = 10; - a = a - 2*SI_DRIVE_STEP; - } else if (a > 0) { // +3dB - setting.rx_drive = 9; - a = a - SI_DRIVE_STEP; - } else - setting.rx_drive = 8; // defined as 0dB level + a = a - POWER_OFFSET; // Move to zero for max power if (a > 0) a = 0; - if( a > - SWITCH_ATTENUATION) { - setting.atten_step = 0; - } else { + if( a < - SWITCH_ATTENUATION) { a = a + SWITCH_ATTENUATION; setting.atten_step = 1; + } else { + setting.atten_step = 0; + } + setting.rx_drive = MAX_DRIVE; // defined as 0dB level + while (a <= - SI_DRIVE_STEP && setting.rx_drive > MIN_DRIVE) { + a += SI_DRIVE_STEP; + setting.rx_drive--; } a = -a; } else { @@ -603,8 +586,8 @@ void set_attenuation(float a) // Is used both in low output mode and high/ } if (a<0.0) a = 0; - if (a> 31) - a=31.0; + if (a> 31.5) + a = 31.5; if (setting.mode == M_HIGH) // No attenuator in high mode a = 0; if (setting.attenuate_x2 == a*2) @@ -742,16 +725,16 @@ void toggle_spur(void) } #endif -#ifdef __ULTRA__ +#ifdef __HARMONIC__ void set_harmonic(int h) { setting.harmonic = h; minFreq = 684000000.0; - if ((uint32_t)(setting.harmonic * 240000000)+434000000 > minFreq) - minFreq = setting.harmonic * 240000000.0+434000000.0; - maxFreq = 4360000000; - if (setting.harmonic != 0 && (960000000.0 * setting.harmonic + 434000000.0 )< 4360000000.0) - maxFreq = (960000000.0 * setting.harmonic + 434000000.0 ); + if ((uint32_t)(setting.harmonic * 135000000)+config.frequency_IF1 > minFreq) + minFreq = setting.harmonic * 135000000 + config.frequency_IF1; + maxFreq = 4290000000.0; + if (setting.harmonic != 0 && (4400000000.0 * setting.harmonic + config.frequency_IF1 )< 4360000000.0) + maxFreq = (4400000000.0 * setting.harmonic + config.frequency_IF1 ); set_sweep_frequency(ST_START, minFreq); set_sweep_frequency(ST_STOP, maxFreq); } @@ -1011,7 +994,7 @@ extern char low_level_help_text[12]; void set_offset(float offset) { setting.offset = offset; - plot_printf(low_level_help_text, sizeof low_level_help_text, "%+d..%+d", -76 + (int)offset, -6 + (int)offset); + plot_printf(low_level_help_text, sizeof low_level_help_text, "%+d..%+d", POWER_OFFSET - 70 + (int)offset, POWER_OFFSET + (int)offset); force_set_markmap(); dirty = true; // No HW update required, only status panel refresh but need to ensure the cached value is updated in the calculation of the RSSI } @@ -1986,19 +1969,27 @@ pureRSSI_t perform(bool break_on_operation, int i, uint32_t f, int tracking) a += PURE_TO_float(get_frequency_correction(f)); if (a != old_a) { old_a = a; - int d = 10; // Start at lowest drive level; - a = a + POWER_OFFSET; - if (a > 0) { - d++; - a = a - SI_DRIVE_STEP; - } - if (a > 0) { - d++; - a = a - SI_DRIVE_STEP; + a = a - POWER_OFFSET; // convert to all settings maximum power output equals a = zero + + if (a < -SWITCH_ATTENUATION) { + a = a + SWITCH_ATTENUATION; +#ifdef TINYSA3 + set_switch_receive(); +#else + enable_rx_output(false); +#endif + } else { +#ifdef TINYSA3 + set_switch_transmit(); +#else + enable_rx_output(true); +#endif } - if (a > 0) { - d++; - a = a - SI_DRIVE_STEP; + + int d = MAX_DRIVE; // Start at highest drive level; + while (a < -SI_DRIVE_STEP && d > MIN_DRIVE) { + d--; // Reduce drive + a = a + SI_DRIVE_STEP; // and compensate } #ifdef __SI4432__ SI4432_Sel = SI4432_RX ; @@ -2007,24 +1998,12 @@ pureRSSI_t perform(bool break_on_operation, int i, uint32_t f, int tracking) #ifdef __SI4463__ SI4463_set_output_level(d); #endif + + if (a > 0) a = 0; - if( a > - SWITCH_ATTENUATION) { -#ifdef TINYSA3 - set_switch_transmit(); -#else - enable_rx_output(true); -#endif - } else { - a = a + SWITCH_ATTENUATION; -#ifdef TINYSA3 - set_switch_receive(); -#else - enable_rx_output(false); -#endif - } - if (a < -31) - a = -31; + if (a < -31.5) + a = -31.5; a = -a; #ifdef __PE4302__ PE4302_Write_Byte((int)(a * 2) ); @@ -2095,7 +2074,7 @@ modulation_again: } // -------------- set ultra --------------------------------- if (setting.mode == M_LOW && config.ultra) { - if ((S_IS_AUTO(setting.ultra)&& f > config.lpf_switch) || S_STATE(setting.ultra) ) { + if ((S_IS_AUTO(setting.ultra)&& f > config.ultra_threshold) || S_STATE(setting.ultra) ) { enable_ultra(true); } else enable_ultra(false); @@ -2119,7 +2098,7 @@ modulation_again: // offs>>=1; // steps of a quarter rbw // if (lf > -offs) // No negative frequencies lf += offs; - if (lf > 4000000000U) + if (lf > 4290000000U) lf = 0; } // -------------- Calculate the IF ----------------------------- @@ -2152,7 +2131,7 @@ modulation_again: } else { #ifdef __SI4468__ if (S_IS_AUTO(setting.spur_removal)) { - if (lf >= config.lpf_switch) { + if (lf >= config.ultra_threshold) { setting.spur_removal= S_AUTO_ON; } else { setting.spur_removal= S_AUTO_OFF; @@ -2232,11 +2211,17 @@ modulation_again: } else #endif { // Else set LO ('s) - uint32_t target_f; - if (setting.mode == M_LOW && !setting.tracking && S_STATE(setting.below_IF)) // if in low input mode and below IF - target_f = local_IF-lf; // set LO SI4432 to below IF frequency + uint64_t target_f; + int inverted_f = false; + if (setting.mode == M_LOW && !setting.tracking && ( S_STATE(setting.below_IF) || (uint64_t)lf + (uint64_t)local_IF> 4290000000U) ) { // if in low input mode and below IF + if (lf < local_IF) + target_f = (uint64_t)local_IF-(uint64_t)lf; // set LO SI4432 to below IF frequency + else + target_f = (uint64_t)lf - (uint64_t)local_IF; // set LO SI4432 to below IF frequency + inverted_f = true; + } else - target_f = local_IF+lf; // otherwise to above IF, local_IF == 0 in high mode + target_f = (uint64_t)local_IF+(uint64_t)lf; // otherwise to above IF, local_IF == 0 in high mode #ifdef __SI4432__ set_freq (SI4432_LO, target_f); // otherwise to above IF #endif @@ -2253,7 +2238,7 @@ modulation_again: #define TXCO_DIV3 10000000 if (setting.R == 0) { - if (lf < 850000000 && lf >= TXCO_DIV3) { + if (lf < 850000000U && lf >= TXCO_DIV3) { uint32_t tf = ((lf + actual_rbw_x10*100) / TCXO) * TCXO; if (tf + actual_rbw_x10*100 >= lf && tf < lf + actual_rbw_x10*100) { // ADF4351_R_counter(8); no impact @@ -2309,16 +2294,34 @@ modulation_again: } else target_f = local_IF+lf; // otherwise to above IF #endif + if (setting.harmonic) { + target_f /= setting.harmonic; + } set_freq(ADF4351_LO, target_f); #if 1 // Compensate frequency ADF4350 error with SI4468 int32_t error_f = 0; if (real_old_freq[ADF4351_LO] > target_f) { error_f = real_old_freq[ADF4351_LO] - target_f; + if (inverted_f) { + error_f = -error_f; + goto correct_min; + } + correct_plus: + if (setting.harmonic) { + error_f *= setting.harmonic; + } if (error_f > actual_rbw_x10 * 5) //RBW / 4 local_IF += error_f; - } - if ( real_old_freq[ADF4351_LO] < target_f) { + } else if ( real_old_freq[ADF4351_LO] < target_f) { error_f = real_old_freq[ADF4351_LO] - target_f; + if (inverted_f) { + error_f = -error_f; + goto correct_plus; + } + correct_min: + if (setting.harmonic) { + error_f *= setting.harmonic; + } if ( error_f < - actual_rbw_x10 * 5) //RBW / 4 local_IF += error_f; } diff --git a/si4432.c b/si4432.c index c114c47..33e05a8 100644 --- a/si4432.c +++ b/si4432.c @@ -1208,7 +1208,7 @@ void ADF4351_aux_drive(int p) registers[4] |= (((unsigned long)p) << 6); ADF4351_Set(0); } - +#if 0 static uint32_t gcd(uint32_t x, uint32_t y) { uint32_t z; @@ -1219,6 +1219,7 @@ static uint32_t gcd(uint32_t x, uint32_t y) } return x; } +#endif #if 0 #endif @@ -2427,7 +2428,7 @@ uint32_t SI4463_set_freq(uint32_t freq) } SI4463_frequency_changed = true; // SI4463_set_gpio(3,GPIO_LOW); - return; + return actual_freq; } #if 0 static int old_R = -1; // What about TX/RX switching? @@ -2494,7 +2495,9 @@ uint32_t SI4463_set_freq(uint32_t freq) // SI4463_clear_int_status(); +#if 0 retry: +#endif if (SI4463_in_tx_mode) SI4463_start_tx(0); else { diff --git a/ui.c b/ui.c index 1022a91..1c41b48 100644 --- a/ui.c +++ b/ui.c @@ -1864,7 +1864,7 @@ draw_menu_buttons(const menuitem_t *menu) local_slider_positions = LCD_WIDTH/2+setting.slider_position; goto draw_slider; } else if (menu[i].data == KM_LOWOUTLEVEL) { - local_slider_positions = (get_attenuation() + 76 ) * MENU_FORM_WIDTH / 70 + OFFSETX; + local_slider_positions = (get_attenuation() - POWER_OFFSET + 70 ) * MENU_FORM_WIDTH / 70 + OFFSETX; goto draw_slider; } } @@ -2019,7 +2019,7 @@ menu_select_touch(int i) check_frequency_slider(slider_freq); } } else if (menu_is_form(menu) && MT_MASK(menu[i].type) == MT_KEYPAD && keypad == KM_LOWOUTLEVEL) { - uistat.value = setting.offset + (touch_x - OFFSETX) *( -6 - -76) / MENU_FORM_WIDTH + -76; + uistat.value = setting.offset + (POWER_OFFSET-70) + (touch_x - OFFSETX) * 70 / MENU_FORM_WIDTH ; set_keypad_value(keypad); apply: perform(false, 0, get_sweep_frequency(ST_CENTER), false); diff --git a/ui_sa.c b/ui_sa.c index 85f7b19..0b5ad3a 100644 --- a/ui_sa.c +++ b/ui_sa.c @@ -457,14 +457,14 @@ static const struct { {keypads_positive , "MODULO"}, // KM_MOD {keypads_positive , "CP"}, // KM_CP {keypads_positive , "ATTACK"}, // KM_ATTACK - {keypads_freq , "LPF"}, // KM_LPF + {keypads_freq , "ULTRA\nSTART"}, // KM_LPF }; #if 0 // Not used ui_slider_t ui_sliders [] = { { KM_CENTER, true, 0, 1000000, 0, 350000000, M_GENLOW}, { KM_CENTER, true, 0, 1000000, 240000000, 960000000, M_GENHIGH}, - { KM_LOWOUTLEVEL, false,0, 1, -76, -6, M_GENLOW}, + { KM_LOWOUTLEVEL, false,0, 1, POWER_OFFSET - 70, POWER_OFFSET, M_GENLOW}, }; #endif @@ -1270,7 +1270,7 @@ static void choose_active_marker(void) active_marker = -1; } -#ifdef __ULTRA__ +#ifdef __HARMONIC__ static UI_FUNCTION_ADV_CALLBACK(menu_harmonic_acb) { (void)item; @@ -1562,7 +1562,7 @@ static const menuitem_t menu_sweep[] = { { MT_FORM | MT_NONE, 0, NULL, NULL } // sentinel }; -char low_level_help_text[12] = "-76..-6"; +char low_level_help_text[12] = "-88..-18"; char center_text[10] = "FREQ: %s"; static const menuitem_t menu_lowoutputmode[] = { @@ -1570,7 +1570,7 @@ static const menuitem_t menu_lowoutputmode[] = { // { MT_FORM | MT_ADV_CALLBACK, 0, "MOD: %s", menu_smodulation_acb}, { MT_FORM | MT_SUBMENU, 255, S_RARROW" Settings", menu_settings3}, { MT_FORM | MT_KEYPAD, KM_CENTER, center_text, "10kHz..350MHz"}, - { MT_FORM | MT_KEYPAD, KM_LOWOUTLEVEL, "LEVEL: %s", low_level_help_text /* "-76..-6" */}, + { MT_FORM | MT_KEYPAD, KM_LOWOUTLEVEL, "LEVEL: %s", low_level_help_text}, { MT_FORM | MT_ADV_CALLBACK, 0, "MOD: %s", menu_smodulation_acb}, { MT_FORM | MT_ADV_CALLBACK, 0, "%s", menu_sweep_acb}, // { MT_FORM | MT_KEYPAD, KM_SPAN, "SPAN: %s", "0..350MHz"}, @@ -1765,9 +1765,10 @@ static const menuitem_t menu_dfu[] = { { MT_FORM | MT_NONE, 0, NULL, NULL } // sentinel }; -#ifdef __ULTRA__ +#ifdef __HARMONIC__ static const menuitem_t menu_harmonic[] = { + { MT_ADV_CALLBACK, 0, "OFF", menu_harmonic_acb}, { MT_ADV_CALLBACK, 2, "2", menu_harmonic_acb}, { MT_ADV_CALLBACK, 3, "3", menu_harmonic_acb}, { MT_ADV_CALLBACK, 4, "4", menu_harmonic_acb}, @@ -1818,7 +1819,7 @@ static const menuitem_t menu_settings3[] = // { MT_KEYPAD, KM_GRIDLINES, "MINIMUM\nGRIDLINES", "Enter minimum horizontal grid divisions"}, { MT_ADV_CALLBACK, 0, "DEBUG\nFREQ", menu_debug_freq_acb}, { MT_ADV_CALLBACK, 0, "ADF OUT", menu_adf_out_acb}, - { MT_KEYPAD, KM_LPF, "LPF", "Enter LPF max freq"}, + { MT_KEYPAD, KM_LPF, "ULTRA\nSTART", "Enter ULTRA mode start freq"}, #if 0 // only used during development { MT_KEYPAD, KM_COR_AM, "COR\nAM", "Enter AM modulation correction"}, { MT_KEYPAD, KM_COR_WFM, "COR\nWFM", "Enter WFM modulation correction"}, @@ -1828,12 +1829,12 @@ static const menuitem_t menu_settings3[] = { MT_KEYPAD, KM_R, "R", "Set R"}, { MT_KEYPAD, KM_MOD, "MODULO", "Set MODULO"}, { MT_KEYPAD, KM_CP, "CP", "Set CP"}, - { MT_ADV_CALLBACK | MT_LOW, 0, "ULTRA", menu_settings_ultra_acb}, + { MT_ADV_CALLBACK | MT_LOW, 0, "ULTRA\nMODE", menu_settings_ultra_acb}, #ifdef __HAM_BAND__ { MT_ADV_CALLBACK, 0, "HAM\nBANDS", menu_settings_ham_bands}, #endif -#ifdef __ULTRA__ +#ifdef __HARMONIC__ { MT_SUBMENU,0, "HARMONIC", menu_harmonic}, #endif { MT_CANCEL, 0, S_LARROW" BACK", NULL }, @@ -2194,10 +2195,10 @@ static void fetch_numeric_target(void) case KM_LOWOUTLEVEL: uistat.value = get_attenuation(); // compensation for dB offset during low output mode int end_level = ((int32_t)uistat.value)+setting.level_sweep; - if (end_level < -76) - end_level = -76; - if (end_level > -6) - end_level = -6; + if (end_level < POWER_OFFSET - 70) + end_level = POWER_OFFSET - 70; + if (end_level > POWER_OFFSET) + end_level = POWER_OFFSET; uistat.value += setting.offset; end_level += setting.offset; if (setting.level_sweep != 0) @@ -2216,7 +2217,7 @@ static void fetch_numeric_target(void) break; #endif case KM_LPF: - uistat.value = config.lpf_switch; + uistat.value = config.ultra_threshold; plot_printf(uistat.text, sizeof uistat.text, "%3.6fMHz", uistat.value / 1000000.0); break; case KM_NOISE: @@ -2352,7 +2353,7 @@ set_numeric_value(void) break; #endif case KM_LPF: - config.lpf_switch = uistat.value; + config.ultra_threshold = uistat.value; config_save(); break; case KM_NOISE: