diff --git a/main.c b/main.c index 78dcd24..4bbe8b6 100644 --- a/main.c +++ b/main.c @@ -880,6 +880,7 @@ config_t config = { .high_level_offset = 100, // Uncalibrated .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 }, + .setting_frequency_10mhz = 10000000, .cor_am = -14, .cor_wfm = -17, .cor_nfm = -17, @@ -1090,8 +1091,8 @@ void set_marker_frequency(int m, uint32_t f) int i = 1; markers[m].mtype &= ~M_TRACKING; uint32_t s = (frequencies[1] - frequencies[0])/2; - while (i< sweep_points - 1){ - if (frequencies[i]-s <= f && f < frequencies[i]+s) { + while (i< sweep_points - 2){ + if (frequencies[i]-s <= f && f < frequencies[i+1]-s) { // Avoid rounding error in s!!!!!!! markers[m].index = i; markers[m].frequency = f; return; diff --git a/nanovna.h b/nanovna.h index 39958ee..1fe740a 100644 --- a/nanovna.h +++ b/nanovna.h @@ -484,6 +484,7 @@ typedef struct config { int8_t cor_am; int8_t cor_wfm; int8_t cor_nfm; + uint32_t setting_frequency_10mhz; int8_t dummy; // uint8_t _reserved[22]; uint32_t checksum; @@ -913,6 +914,7 @@ typedef struct uistat { uint8_t marker_delta; uint8_t marker_noise; uint8_t marker_tracking; + uint8_t auto_center_marker; char text[20]; } uistat_t; diff --git a/plot.c b/plot.c index 774e110..28dcc3a 100644 --- a/plot.c +++ b/plot.c @@ -2117,12 +2117,18 @@ static void cell_draw_marker_info(int x0, int y0) if (delta < -5 || delta > 5) break; float level = (actual_t[markers[1].index] + actual_t[markers[2].index])/2.0 - actual_t[markers[0].index]; - if (level < -40 || level > 0) + if (level < -70 || level > 0) break; int depth =(int) (pow((float)10.0, 2.0 + (level + 6.02) /20.0)); #endif plot_printf(buf, sizeof buf, "DEPTH: %3d%%", depth); goto show_computed; + } else if (setting.measurement == M_FM){ + int32_t dev = ( markers[2].frequency - markers[1].frequency - actual_rbw_x10 * 100 ) >> 1; + if (dev < 0 ) + break; + plot_printf(buf, sizeof buf, "DEVIATION:%6.1qHz", dev); + goto show_computed; } } if (i >= 2 && setting.measurement == M_THD) { diff --git a/sa_core.c b/sa_core.c index a72169f..58e4f2e 100644 --- a/sa_core.c +++ b/sa_core.c @@ -270,6 +270,19 @@ void set_gridlines(int d) update_grid(); } +//int setting_frequency_10mhz = 10000000; + +void set_10mhz(uint32_t f) +{ + if (f < 9000000 || f > 11000000) + return; + config.setting_frequency_10mhz = f; + config_save(); + dirty = true; + update_grid(); +} + + void set_measurement(int m) { setting.measurement = m; @@ -705,23 +718,36 @@ void toggle_AGC(void) dirty = true; } +#ifdef __SI4432__ +static unsigned char SI4432_old_v[2]; +#endif + void auto_set_AGC_LNA(int auto_set, int agc) // Adapt the AGC setting if needed { #ifdef __SI4432__ - static unsigned char old_v[2]; unsigned char v; if (auto_set) v = 0x60; // Enable AGC and disable LNA else v = 0x40+agc; // Disable AGC and enable LNA - if (old_v[MODE_SELECT(setting.mode)] != v) { + if (SI4432_old_v[MODE_SELECT(setting.mode)] != v) { SI4432_Sel = MODE_SELECT(setting.mode); SI4432_Write_Byte(SI4432_AGC_OVERRIDE, v); - old_v[MODE_SELECT(setting.mode)] = v; + SI4432_old_v[MODE_SELECT(setting.mode)] = v; } #endif } +#ifdef __SI4432__ +void set_AGC_LNA(void) { + unsigned char v = 0x40; + if (S_STATE(setting.agc)) v |= 0x20; + if (S_STATE(setting.lna)) v |= 0x10; + SI4432_Write_Byte(SI4432_AGC_OVERRIDE, v); + SI4432_old_v[MODE_SELECT(setting.mode)] = v; +} +#endif + void set_unit(int u) { if (setting.unit == u) @@ -1210,12 +1236,6 @@ void set_switch_off(void) { SI4432_Write_Byte(SI4432_GPIO1_CONF, 0x1f); } -void set_AGC_LNA(void) { - unsigned char v = 0x40; - if (S_STATE(setting.agc)) v |= 0x20; - if (S_STATE(setting.lna)) v |= 0x10; - SI4432_Write_Byte(SI4432_AGC_OVERRIDE, v); -} #endif void set_switches(int m) @@ -1389,6 +1409,21 @@ int binary_search_frequency(int f) // Search which index in the frequency t return -1; } +uint32_t interpolate_maximum(int m) +{ + const int idx = markers[m].index; + markers[m].frequency = frequencies[idx]; + if (idx > 0 && idx < sweep_points-1) + { + const float y1 = actual_t[idx - 1]; + const float y2 = actual_t[idx + 0]; + const float y3 = actual_t[idx + 1]; + const float d = 0.5f * (y1 - y3) / ((y1 - (2 * y2) + y3) + 1e-12f); + //const float bin = (float)idx + d; + const int32_t delta_Hz = abs((int64_t)frequencies[idx + 0] - frequencies[idx + 1]); + markers[m].frequency += (int32_t)(delta_Hz * d); + } +} #define MAX_MAX 4 int @@ -1453,7 +1488,8 @@ search_maximum(int m, int center, int span) } } markers[m].index = max_index[0]; - markers[m].frequency = frequencies[markers[m].index]; + interpolate_maximum(m); +// markers[m].frequency = frequencies[markers[m].index]; return found; } @@ -1590,6 +1626,22 @@ static pureRSSI_t correct_RSSI; static pureRSSI_t correct_RSSI_freq; systime_t start_of_sweep_timestamp; static systime_t sweep_elapsed = 0; // Time since first start of sweeping, used only for auto attenuate +static uint8_t signal_is_AM = false; +static uint8_t check_for_AM = false; + +static void calculate_static_correction(void) // Calculate the static part of the RSSI correction +{ + correct_RSSI = +#ifdef __SI4432__ + getSI4432_RSSI_correction() +#endif + - get_signal_path_loss() + + float_TO_PURE_RSSI( + + get_level_offset() + + get_attenuation() + - setting.offset); +} + pureRSSI_t perform(bool break_on_operation, int i, uint32_t f, int tracking) // Measure the RSSI for one frequency, used from sweep and other measurement routines. Must do all HW setup { @@ -1624,15 +1676,7 @@ pureRSSI_t perform(bool break_on_operation, int i, uint32_t f, int tracking) // setting.sweep_time_us = setting.actual_sweep_time_us; } if (MODE_INPUT(setting.mode)) { - correct_RSSI = -#ifdef __SI4432__ - getSI4432_RSSI_correction() -#endif - - get_signal_path_loss() - + float_TO_PURE_RSSI( - + get_level_offset() - + get_attenuation() - - setting.offset); + calculate_static_correction(); } // if (MODE_OUTPUT(setting.mode) && setting.additional_step_delay_us < 500) // Minimum wait time to prevent LO from lockup during output frequency sweep // setting.additional_step_delay_us = 500; @@ -1690,7 +1734,7 @@ pureRSSI_t perform(bool break_on_operation, int i, uint32_t f, int tracking) #endif } } - if (setting.mode == M_LOW && S_IS_AUTO(setting.agc) && UNIT_IS_LOG(setting.unit)) { // If in low input mode with auto AGC and log unit + if (setting.mode == M_LOW && S_IS_AUTO(setting.agc) && !check_for_AM && UNIT_IS_LOG(setting.unit)) { // If in low input mode with auto AGC and log unit if (f < 1500000) auto_set_AGC_LNA(false, f*9/1500000); else @@ -2056,6 +2100,10 @@ static bool sweep(bool break_on_operation) uint32_t agc_peak_freq = 0; float agc_peak_rssi = -150; float agc_prev_rssi = -150; + int last_AGC_value = 0; + uint8_t last_AGC_direction_up = false; + int AGC_flip_count = 0; + // if (setting.mode== -1) // return; // START_PROFILE; @@ -2072,9 +2120,15 @@ static bool sweep(bool break_on_operation) modulation_counter = 0; // init modulation counter in case needed int refreshing = false; - if (dirty) // Calculate new scanning solution + if (dirty) { // Calculate new scanning solution sweep_counter = 0; - else if ( MODE_INPUT(setting.mode) && setting.frequency_step > 0) { + if (get_sweep_frequency(ST_SPAN) < 300000) // Check if AM signal + check_for_AM = true; + else { + signal_is_AM = false; + check_for_AM = false; + } + } else if ( MODE_INPUT(setting.mode) && setting.frequency_step > 0) { sweep_counter++; if (sweep_counter > 50 ) { // refresh HW after 50 sweeps dirty = true; @@ -2154,6 +2208,16 @@ sweep_again: // stay in sweep loop when output mo #ifdef __DEBUG_AGC__ // For debugging the AGC control stored_t[i] = (SI4432_Read_Byte(0x69) & 0x01f) * 3.0 - 90.0; // Display the AGC value in the stored trace #endif + + if (check_for_AM) { + int AGC_value = (SI4432_Read_Byte(0x69) & 0x01f) * 3.0 - 90.0; + if (AGC_value < last_AGC_value && last_AGC_direction_up ) { + AGC_flip_count++; + } else if (AGC_value > last_AGC_value && !last_AGC_direction_up ) { + AGC_flip_count++; + } + last_AGC_value = AGC_value; + } if (scandirty || setting.average == AV_OFF) { // Level calculations actual_t[i] = RSSI; age[i] = 0; @@ -2363,27 +2427,47 @@ sweep_again: // stay in sweep loop when output mo redraw_request |= REDRAW_CAL_STATUS; #ifdef __SI4432__ SI4432_Sel = SI4432_RX ; +#if 0 // this should never happen if (setting.atten_step) { set_switch_transmit(); // This should never happen } else { set_switch_receive(); } #endif - dirty = true; // Needed to recalculate the correction factor +#endif + calculate_static_correction(); // Update correction +// dirty = true; // Needed to recalculate the correction factor } } // ---------------------------------- auto AGC ---------------------------------- - if (!in_selftest && MODE_INPUT(setting.mode) && S_IS_AUTO(setting.agc)) { - float actual_max_level = actual_t[max_index[0]] - get_attenuation(); - if (UNIT_IS_LINEAR(setting.unit)) { // Auto AGC in linear mode - if (actual_max_level > - 45) - auto_set_AGC_LNA(false, 0); // Strong signal, no AGC and no LNA - else - auto_set_AGC_LNA(TRUE, 0); - } + if (!in_selftest && MODE_INPUT(setting.mode)) { + if (S_IS_AUTO(setting.agc)) { + float actual_max_level = actual_t[max_index[0]] - get_attenuation(); + if (UNIT_IS_LINEAR(setting.unit)) { // Auto AGC in linear mode + if (actual_max_level > - 45) + auto_set_AGC_LNA(false, 0); // Strong signal, no AGC and no LNA + else + auto_set_AGC_LNA(TRUE, 0); + } + if (check_for_AM) { + if (signal_is_AM) { + if (actual_max_level < - 40 ) + signal_is_AM = false; + } else { + if (AGC_flip_count > 20 && actual_max_level >= - 40) + signal_is_AM = true; + } + if (signal_is_AM) { // if log mode and AM signal + auto_set_AGC_LNA(false, 16); // LNA on and no AGC + } else { + auto_set_AGC_LNA(TRUE, 0); + } + } + } else + signal_is_AM = false; } @@ -2447,7 +2531,8 @@ sweep_again: // stay in sweep loop when output mo while (m < MARKERS_MAX) { if (markers[m].enabled && markers[m].mtype & M_TRACKING) { // Available marker found markers[m].index = max_index[i]; - markers[m].frequency = frequencies[markers[m].index]; + interpolate_maximum(m); + // markers[m].frequency = frequencies[markers[m].index]; #if 0 float v = actual_t[markers[m].index] - 10.0; // -10dB points int index = markers[m].index; @@ -2469,19 +2554,7 @@ sweep_again: // stay in sweep loop when output mo #endif -#if 1 // Hyperbolic interpolation, can be removed to save memory - const int idx = markers[m].index; - if (idx > 0 && idx < sweep_points-1) - { - const float y1 = actual_t[idx - 1]; - const float y2 = actual_t[idx + 0]; - const float y3 = actual_t[idx + 1]; - const float d = 0.5f * (y1 - y3) / ((y1 - (2 * y2) + y3) + 1e-12f); - //const float bin = (float)idx + d; - const int32_t delta_Hz = abs((int64_t)frequencies[idx + 0] - frequencies[idx + 1]); - markers[m].frequency += (int32_t)(delta_Hz * d); - } -#endif + interpolate_maximum(m); m++; break; // Next maximum } @@ -2492,7 +2565,7 @@ sweep_again: // stay in sweep loop when output mo while (m < MARKERS_MAX) { // Insufficient maxima found if (markers[m].enabled && markers[m].mtype & M_TRACKING) { // More available markers found markers[m].index = 0; // Enabled but no max so set to left most frequency - markers[m].frequency = frequencies[markers[m].index]; + markers[m].frequency = frequencies[0]; } m++; // Try next marker } @@ -2531,7 +2604,7 @@ sweep_again: // stay in sweep loop when output mo markers[2].index = marker_search_right_min(markers[0].index); if (markers[2].index < 0) markers[1].index = setting._sweep_points - 1; markers[2].frequency = frequencies[markers[2].index]; - } else if (setting.measurement == M_PASS_BAND && markers[0].index > 10) { // ----------------Pass band measurement + } else if ((setting.measurement == M_PASS_BAND || setting.measurement == M_FM) && markers[0].index > 10) { // ----------------Pass band measurement int t = 0; float v = actual_t[markers[0].index] - 3.0; while (t < markers[0].index && actual_t[t+1] < v) // Find left -3dB point @@ -2893,6 +2966,13 @@ void draw_cal_status(void) ili9341_drawstring("ARMED", x, y); } + if (signal_is_AM) { + color = BRIGHT_COLOR_RED; + ili9341_set_foreground(color); + y += YSTEP + YSTEP/2 ; + ili9341_drawstring("AM", x, y); + } + // if (setting.mode == M_LOW) { // Attenuation if (setting.auto_attenuation) @@ -3580,6 +3660,7 @@ void self_test(int test) ili9341_clear_screen(); reset_settings(M_LOW); set_refer_output(-1); +#ifdef DOESNOTFIT } else if (test == 1) { float p2, p1, p; in_selftest = true; // Spur search @@ -3747,9 +3828,7 @@ void self_test(int test) reset_settings(M_LOW); setting.step_delay_mode = SD_NORMAL; setting.step_delay = 0; - } -#ifdef DOESNOTFIT - else if (test == 5) { + } else if (test == 5) { // reset_settings(M_LOW); // Make sure we are in a defined state in_selftest = true; switch (setting.test_argument) { @@ -3786,8 +3865,8 @@ void self_test(int test) break; } in_selftest = false; - } #endif + } show_test_info = FALSE; in_selftest = false; test_wait = false; diff --git a/si4432.c b/si4432.c index 0b3d592..50e9aea 100644 --- a/si4432.c +++ b/si4432.c @@ -208,14 +208,6 @@ static void shiftOutBuf(uint8_t *buf, uint16_t size) { } #endif -//float setting_frequency_10mhz = 1000000.0; - -void set_10mhz(float f) -{ - config.setting_frequency_10mhz = f; - config_save(); -} - int SI4432_step_delay = 1500; int SI4432_offset_delay = 1500; #define MINIMUM_WAIT_FOR_RSSI 280 @@ -474,8 +466,8 @@ void SI4432_Set_Frequency ( uint32_t Freq ) { hbsel = 0; } uint8_t sbsel = 1 << 6; - uint32_t N = (Freq / setting_frequency_10mhz - 24)&0x1F; - uint32_t K = Freq % setting_frequency_10mhz; + uint32_t N = (Freq / config.setting_frequency_10mhz - 24)&0x1F; + uint32_t K = Freq % config.setting_frequency_10mhz; uint32_t Carrier = (K<<2) / 625; uint8_t Freq_Band = N | hbsel | sbsel; // int count = 0; diff --git a/ui.c b/ui.c index 95c57ae..2ee77bd 100644 --- a/ui.c +++ b/ui.c @@ -32,6 +32,7 @@ uistat_t uistat = { marker_delta: FALSE, marker_noise: FALSE, marker_tracking : FALSE, + auto_center_marker : FALSE, text : "", }; @@ -332,7 +333,8 @@ touch_cal_exec(void) ili9341_clear_screen(); ili9341_line(0, 0, 0, 32); ili9341_line(0, 0, 32, 0); - ili9341_drawstring("TOUCH UPPER LEFT", 10, 10); + ili9341_line(0, 0, 32, 32); + ili9341_drawstring("TOUCH UPPER LEFT", 40, 40); touch_wait_release(); x1 = last_touch_x; @@ -341,7 +343,8 @@ touch_cal_exec(void) ili9341_clear_screen(); ili9341_line(LCD_WIDTH-1, LCD_HEIGHT-1, LCD_WIDTH-1, LCD_HEIGHT-32); ili9341_line(LCD_WIDTH-1, LCD_HEIGHT-1, LCD_WIDTH-32, LCD_HEIGHT-1); - ili9341_drawstring("TOUCH LOWER RIGHT", 230, 220); + ili9341_line(LCD_WIDTH-1, LCD_HEIGHT-1, LCD_WIDTH-32, LCD_HEIGHT-32); + ili9341_drawstring("TOUCH LOWER RIGHT", 210, 200); touch_wait_release(); x2 = last_touch_x; @@ -798,6 +801,10 @@ static UI_FUNCTION_CALLBACK(menu_marker_op_cb) case 1: /* MARKER->STOP */ case 2: /* MARKER->CENTER */ set_sweep_frequency(data, freq); + if (data == 2) { + uistat.lever_mode = LM_SPAN; + uistat.auto_center_marker = true; + } break; case 3: /* MARKERS->SPAN */ { @@ -870,7 +877,10 @@ static UI_FUNCTION_CALLBACK(menu_marker_search_cb) } if (i != -1) { markers[active_marker].index = i; - markers[active_marker].frequency = frequencies[i]; + if (data > 1) // Maximum related + interpolate_maximum(active_marker); + else + markers[active_marker].frequency = frequencies[i]; } draw_menu(); redraw_marker(active_marker); @@ -1306,6 +1316,7 @@ menu_invoke(int item) break; case MT_CALLBACK: { + uistat.auto_center_marker = false; menuaction_cb_t cb = (menuaction_cb_t)menu->reference; if (cb) (*cb)(item, menu->data); // if (!(menu->type & MT_FORM)) @@ -1313,6 +1324,7 @@ menu_invoke(int item) break; } case MT_ADV_CALLBACK: { + uistat.auto_center_marker = false; menuaction_acb_t cb = (menuaction_acb_t)menu->reference; if (cb) (*cb)(item, menu->data, NULL); // if (!(menu->type & MT_FORM)) @@ -1324,6 +1336,7 @@ menu_invoke(int item) break; case MT_KEYPAD: + uistat.auto_center_marker = false; if (menu->type & MT_FORM) { area_width = AREA_WIDTH_NORMAL - MENU_BUTTON_WIDTH; redraw_frame(); // Remove form numbers @@ -2137,7 +2150,8 @@ lever_search_marker(int status) i = marker_search_right_max(markers[active_marker].index); if (i != -1) { markers[active_marker].index = i; - markers[active_marker].frequency = frequencies[i]; + interpolate_maximum(active_marker); +// markers[active_marker].frequency = frequencies[i]; } redraw_marker(active_marker); } @@ -2167,6 +2181,12 @@ static void lever_zoom_span(int status) { uint32_t span = get_sweep_frequency(ST_SPAN); + if (uistat.auto_center_marker) { + uint32_t freq = get_marker_frequency(active_marker); + search_maximum(active_marker, freq, 10 ); + if (freq != 0) + set_sweep_frequency(ST_CENTER, freq); + } if (status & EVT_UP) { span = step_round(span - 1); } else if (status & EVT_DOWN) { @@ -2229,7 +2249,7 @@ ui_process_normal(void) if (status & EVT_BUTTON_SINGLE_CLICK) { ui_mode_menu(); } else { - switch (uistat.lever_mode) { + switch (uistat.lever_mode) { case LM_MARKER: lever_move_marker(status); break; case LM_SEARCH: lever_search_marker(status); break; case LM_CENTER: diff --git a/ui_sa.c b/ui_sa.c index e8d7c1e..1f0f1cf 100644 --- a/ui_sa.c +++ b/ui_sa.c @@ -761,7 +761,7 @@ static UI_FUNCTION_ADV_CALLBACK(menu_measure_acb) #ifdef __MEASURE__ switch(data) { case M_OFF: // Off - reset_settings(setting.mode); +// reset_settings(setting.mode); set_measurement(M_OFF); break; case M_IMD: // IMD @@ -836,7 +836,7 @@ static UI_FUNCTION_ADV_CALLBACK(menu_measure_acb) // SetAverage(4); break; - case M_PASS_BAND: // STop band measurement + case M_PASS_BAND: // Stop band measurement // reset_settings(setting.mode); markers[0].enabled = M_ENABLED; markers[0].mtype = M_REFERENCE | M_TRACKING; @@ -870,32 +870,44 @@ static UI_FUNCTION_ADV_CALLBACK(menu_measure_acb) ui_mode_keypad(KM_CENTER); ui_process_keypad(); center = uistat.value; - kp_help_text = "Modulation frequency, 2 .. 10 kHz"; + kp_help_text = "Modulation frequency, 3 .. 10 kHz"; ui_mode_keypad(KM_SPAN); ui_process_keypad(); - if (uistat.value < 2000) + if (uistat.value < 3000) break; - span = uistat.value + 1500; // Enlarge span for RBW width - set_sweep_frequency(ST_SPAN, 100000); // 100kHz + span = uistat.value; + set_sweep_frequency(ST_SPAN, 50000); // 100kHz +// update_frequencies(); // To ensure markers are positioned right!!!!!! set_measurement(M_AM); set_marker_frequency(0, center); set_marker_frequency(1, center-span); set_marker_frequency(2, center+span); + set_average(4); break; case M_FM: // FM reset_settings(setting.mode); for (int i = 0; i< 3; i++) { markers[i].enabled = M_ENABLED; - markers[i].mtype = M_DELTA | M_TRACKING; + markers[i].mtype = M_DELTA; } - markers[0].mtype = M_REFERENCE | M_TRACKING; + markers[0].mtype = M_REFERENCE; kp_help_text = "Frequency of signal"; ui_mode_keypad(KM_CENTER); ui_process_keypad(); - kp_help_text = "Frequency deviation"; + set_marker_frequency(0, uistat.value); + kp_help_text = "Modulation frequency: 1 .. 2.5kHz"; ui_mode_keypad(KM_SPAN); ui_process_keypad(); - set_sweep_frequency(ST_SPAN, uistat.value*30); + if (uistat.value < 1000 || uistat.value > 2500) + break; + set_RBW(uistat.value/100); + // actual_rbw_x10 + kp_help_text = "Frequency deviation: 3 .. 500kHz"; + ui_mode_keypad(KM_SPAN); + ui_process_keypad(); + if (uistat.value < 12000) + uistat.value = 12000; // minimum span + set_sweep_frequency(ST_SPAN, uistat.value*4); set_measurement(M_FM); break; case M_THD: @@ -1015,6 +1027,7 @@ static UI_FUNCTION_ADV_CALLBACK(menu_marker_select_acb) return; } markers[data-1].enabled = true; +// interpolate_maximum(data-1); // possibly not a maximum markers[data-1].frequency = frequencies[markers[data-1].index]; active_marker_select(data-1); menu_push_submenu(menu_marker_modify); @@ -2150,7 +2163,6 @@ set_numeric_value(void) break; case KM_10MHZ: set_10mhz(uistat.value); - dirty = true; break; case KM_OFFSET: set_offset(uistat.value);