diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 3d919bbe..c6ccb817 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -145,6 +145,9 @@ SetRadioView::SetRadioView( add_children({ &check_clkout, + &field_clkout_freq, + &labels_clkout_khz, + &value_freq_step, &labels_bias, &check_bias, &button_done, @@ -165,6 +168,31 @@ SetRadioView::SetRadioView( EventDispatcher::send_message(message); }; + field_clkout_freq.set_value(portapack::persistent_memory::clkout_freq()); + value_freq_step.set_style(&style_text); + + field_clkout_freq.on_select = [this](NumberField&) { + freq_step_khz++; + if(freq_step_khz > 3) { + freq_step_khz = 0; + } + switch(freq_step_khz) { + case 0: + value_freq_step.set(" |"); + break; + case 1: + value_freq_step.set(" | "); + break; + case 2: + value_freq_step.set(" | "); + break; + case 3: + value_freq_step.set("| "); + break; + } + field_clkout_freq.set_step(pow(10, freq_step_khz)); + }; + check_bias.set_value(portapack::get_antenna_bias()); check_bias.on_select = [this](Checkbox&, bool v) { portapack::set_antenna_bias(v); @@ -175,6 +203,8 @@ SetRadioView::SetRadioView( button_done.on_select = [this, &nav](Button&){ const auto model = this->form_collect(); portapack::persistent_memory::set_correction_ppb(model.ppm * 1000); + portapack::persistent_memory::set_clkout_freq(model.freq); + clock_manager.enable_clock_output(portapack::persistent_memory::clkout_enabled()); nav.pop(); }; } @@ -190,6 +220,7 @@ void SetRadioView::form_init(const SetFrequencyCorrectionModel& model) { SetFrequencyCorrectionModel SetRadioView::form_collect() { return { .ppm = static_cast(field_ppm.value()), + .freq = static_cast(field_clkout_freq.value()), }; } diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 4b9f99d4..c66ccd2b 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -114,6 +114,7 @@ private: struct SetFrequencyCorrectionModel { int8_t ppm; + uint32_t freq; }; class SetRadioView : public View { @@ -130,6 +131,7 @@ private: .background = Color::black(), .foreground = Color::light_grey(), }; + uint8_t freq_step_khz = 3; Text label_source { { 0, 1 * 16, 17 * 8, 16 }, @@ -152,9 +154,26 @@ private: }; Checkbox check_clkout { - { 28, (6 * 16 - 4) }, - 4, - "Enable 10MHz CLKOUT" + { 18, (6 * 16 - 4) }, + 13, + "Enable CLKOUT" + }; + + NumberField field_clkout_freq { + { 20 * 8, 6 * 16 }, + 5, + { 10, 60000 }, + 1000, + ' ' + }; + + Labels labels_clkout_khz { + { { 26 * 8, 6 * 16 }, "kHz", Color::light_grey() } + }; + + Text value_freq_step { + { 21 * 8, (7 * 16 ), 4 * 8, 16 }, + "| " }; Labels labels_bias { diff --git a/firmware/application/clock_manager.cpp b/firmware/application/clock_manager.cpp index ec08452b..93eecc13 100644 --- a/firmware/application/clock_manager.cpp +++ b/firmware/application/clock_manager.cpp @@ -21,6 +21,7 @@ #include "clock_manager.hpp" +#include "portapack_persistent_memory.hpp" #include "portapack_io.hpp" #include "hackrf_hal.hpp" @@ -467,7 +468,11 @@ void ClockManager::stop_audio_pll() { void ClockManager::enable_clock_output(bool enable) { if(enable) { clock_generator.enable_output(clock_generator_output_clkout); - clock_generator.set_ms_frequency(clock_generator_output_clkout, 10000000, si5351_vco_f, 0); + if(portapack::persistent_memory::clkout_freq() < 1000) { + clock_generator.set_ms_frequency(clock_generator_output_clkout, portapack::persistent_memory::clkout_freq() * 128000, si5351_vco_f, 7); + } else { + clock_generator.set_ms_frequency(clock_generator_output_clkout, portapack::persistent_memory::clkout_freq() * 1000, si5351_vco_f, 0); + } } else { clock_generator.disable_output(clock_generator_output_clkout); } diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index b25cc894..48486f1a 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -63,6 +63,10 @@ using modem_repeat_range_t = range_t; constexpr modem_repeat_range_t modem_repeat_range { 1, 99 }; constexpr int32_t modem_repeat_reset_value { 5 }; +using clkout_freq_range_t = range_t; +constexpr clkout_freq_range_t clkout_freq_range { 10, 60000 }; +constexpr uint32_t clkout_freq_reset_value { 10000 }; + /* struct must pack the same way on M4 and M0 cores. */ struct data_t { int64_t tuned_frequency; @@ -295,5 +299,20 @@ void set_clkout_enabled(bool enable) { data->ui_config = (data->ui_config & ~0x08000000UL) | (enable << 27); } +uint32_t clkout_freq() { + uint16_t freq = (data->ui_config & 0x000FFFF0) >> 4; + if(freq < clkout_freq_range.minimum || freq > clkout_freq_range.maximum) { + data->ui_config = (data->ui_config & ~0x000FFFF0) | clkout_freq_reset_value << 4; + return clkout_freq_reset_value; + } + else { + return freq; + } +} + +void set_clkout_freq(uint32_t freq) { + data->ui_config = (data->ui_config & ~0x000FFFF0) | (clkout_freq_range.clip(freq) << 4); +} + } /* namespace persistent_memory */ } /* namespace portapack */ diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 6422567a..c05489b0 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -95,6 +95,8 @@ void set_pocsag_ignore_address(uint32_t address); bool clkout_enabled(); void set_clkout_enabled(bool enable); +uint32_t clkout_freq(); +void set_clkout_freq(uint32_t freq); } /* namespace persistent_memory */ } /* namespace portapack */