diff --git a/firmware/application/apps/replay_app.cpp b/firmware/application/apps/replay_app.cpp index 9147c46f..4313b8e7 100644 --- a/firmware/application/apps/replay_app.cpp +++ b/firmware/application/apps/replay_app.cpp @@ -201,6 +201,16 @@ ReplayAppView::ReplayAppView( tx_gain = 35;field_rfgain.set_value(tx_gain); // Initial default value (-12 dB's max ). field_rfamp.set_value(rf_amp ? 14 : 0); // Initial default value True. (TX RF amp on , +14dB's) + field_rfamp.on_change = [this](int32_t v) { // allow initial value change just after opened file. + rf_amp = (bool)v; + }; + field_rfamp.set_value(rf_amp ? 14 : 0); + + field_rfgain.on_change = [this](int32_t v) { // allow initial value change just after opened file. + tx_gain = v; + }; + field_rfgain.set_value(tx_gain); + baseband::run_image(portapack::spi_flash::image_tag_replay); add_children({ diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index bda0f278..68d98212 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -186,7 +186,7 @@ void MicTXView::rxaudio(bool is_on) { baseband::run_image(portapack::spi_flash::image_tag_mic_tx); audio::output::stop(); - audio::input::start(ak4951_alc_GUI_selected); // set up audio input = mic config of any audio coded AK4951/WM8731, (in WM8731 parameter will be ignored) + audio::input::start(); // set up audio input = mic config of any audio coded AK4951/WM8731, (in WM8731 parameter will be ignored) portapack::pin_i2s0_rx_sda.mode(3); configure_baseband(); } @@ -212,7 +212,7 @@ MicTXView::MicTXView( baseband::run_image(portapack::spi_flash::image_tag_mic_tx); - if ( audio_codec_wm8731.detected() ) { + if (true ) { // Temporary , disabling ALC feature , (pending to solve -No Audio in Mic app ,in some H2/H2+ WM /QFP100 CPLS users- if ( audio_codec_wm8731.detected() ) { add_children({ &labels_WM8731, // we have audio codec WM8731, same MIC menu as original. &vumeter, @@ -285,7 +285,7 @@ MicTXView::MicTXView( options_ak4951_alc_mode.on_change = [this](size_t, int8_t v) { ak4951_alc_GUI_selected = v; - audio::input::start(ak4951_alc_GUI_selected); + audio::input::start(); }; // options_ak4951_alc_mode.set_selected_index(0); @@ -341,23 +341,37 @@ MicTXView::MicTXView( enable_dsb = false; field_bw.set_value(transmitter_model.channel_bandwidth() / 1000); //if (rx_enabled) - rxaudio(rx_enabled); //Update now if we have RX audio on + rxaudio(rx_enabled); //Update now if we have RX audio on + options_tone_key.hidden(0); // we are in FM mode , we should have active the Key-tones & CTCSS option. + field_rxbw.hidden(0); // we are in FM mode, we need to allow the user set up of the RX NFM BW selection (8K5, 11K, 16K) break; case 1: enable_am = true; - rxaudio(rx_enabled); //Update now if we have RX audio on + rxaudio(rx_enabled); //Update now if we have RX audio on + options_tone_key.set_selected_index(0); // we are NOT in FM mode , we reset the possible previous key-tones &CTCSS selection. + set_dirty(); // Refresh display + options_tone_key.hidden(1); // we hide that Key-tones & CTCSS input selecction, (no meaning in AM/DSB/SSB). + field_rxbw.hidden(1); // we hide the NFM BW selection in other modes non_FM (no meaning in AM/DSB/SSB) + check_rogerbeep.hidden(0); // make visible again the "rogerbeep" selection. break; case 2: enable_usb = true; - rxaudio(rx_enabled); //Update now if we have RX audio on + rxaudio(rx_enabled); //Update now if we have RX audio on + check_rogerbeep.set_value(false); // reset the possible activation of roger beep, because it is not compatible with SSB , by now. + check_rogerbeep.hidden(1); // hide that roger beep selection. + set_dirty(); // Refresh display break; case 3: enable_lsb = true; - rxaudio(rx_enabled); //Update now if we have RX audio on + rxaudio(rx_enabled); //Update now if we have RX audio on + check_rogerbeep.set_value(false); // reset the possible activation of roger beep, because it is not compatible with SSB , by now. + check_rogerbeep.hidden(1); // hide that roger beep selection. + set_dirty(); // Refresh display break; case 4: enable_dsb = true; - rxaudio(rx_enabled); //Update now if we have RX audio on + rxaudio(rx_enabled); //Update now if we have RX audio on + check_rogerbeep.hidden(0); // make visible again the "rogerbeep" selection. break; } //configure_baseband(); @@ -525,7 +539,7 @@ MicTXView::MicTXView( set_tx(false); audio::set_rate(audio::Rate::Hz_24000); - audio::input::start(ak4951_alc_GUI_selected); // originally , audio::input::start(); (we added parameter) + audio::input::start(); // originally , audio::input::start(); (we added parameter) } MicTXView::~MicTXView() { diff --git a/firmware/application/audio.cpp b/firmware/application/audio.cpp index ce32076c..4ba23acc 100644 --- a/firmware/application/audio.cpp +++ b/firmware/application/audio.cpp @@ -168,8 +168,8 @@ void speaker_mute() { namespace input { -void start(int8_t alc_mode) { - audio_codec->microphone_enable(alc_mode); // added user-GUI selection for AK4951, ALC mode parameter. +void start() { + audio_codec->microphone_enable(); i2s::i2s0::rx_start(); } diff --git a/firmware/application/audio.hpp b/firmware/application/audio.hpp index 56301ee8..b02e42aa 100644 --- a/firmware/application/audio.hpp +++ b/firmware/application/audio.hpp @@ -49,7 +49,7 @@ public: virtual volume_range_t headphone_gain_range() const = 0; virtual void set_headphone_volume(const volume_t volume) = 0; - virtual void microphone_enable(int8_t alc_mode) = 0; // added user-GUI AK4951 ,selected ALC mode. + virtual void microphone_enable() = 0; virtual void microphone_disable() = 0; virtual size_t reg_count() const = 0; @@ -59,7 +59,7 @@ public: namespace output { -void start(); // this other start(),no changed. ,in namespace output , used to config audio playback mode, +void start(); void stop(); void mute(); @@ -72,7 +72,7 @@ void speaker_unmute(); namespace input { -void start(int8_t alc_mode); // added parameter user-GUI select AK4951-ALC mode for config mic path,(recording mode in datasheet), +void start(); void stop(); } /* namespace input */ diff --git a/firmware/baseband/dsp_modulate.cpp b/firmware/baseband/dsp_modulate.cpp index 31dd3f85..04102800 100644 --- a/firmware/baseband/dsp_modulate.cpp +++ b/firmware/baseband/dsp_modulate.cpp @@ -21,6 +21,8 @@ #include "dsp_modulate.hpp" #include "sine_table_int8.hpp" +#include "portapack_shared_memory.hpp" +#include "tonesets.hpp" namespace dsp { namespace modulate { @@ -40,13 +42,42 @@ void Modulator::set_over(uint32_t new_over) { over = new_over; } +void Modulator::set_gain_vumeter_beep(float new_audio_gain , bool new_play_beep ) { + audio_gain = new_audio_gain ; + play_beep = new_play_beep; + +} + +int32_t Modulator::apply_beep(int32_t sample_in, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message ) { + + if (play_beep) { // We need to add audio beep sample. + if (new_beep_timer) { + new_beep_timer--; + } else { + new_beep_timer = baseband_fs * 0.05; // 50ms + + if (new_beep_index == BEEP_TONES_NB) { + configured_in = false; + shared_memory.application_queue.push(new_txprogress_message); + } else { + beep_gen.configure(beep_deltas[new_beep_index], 1.0); // config sequentially the audio beep tone. + new_beep_index++; + } + } + sample_in = beep_gen.process(0); // Get sample of the selected sequence of 6 beep tones , and overwrite audio sample. Mix 0%. + } + return sample_in; // Return audio mic scaled with gain , 8 bit sample or audio beep sample. +} + + /// SSB::SSB() : hilbert() { mode = Mode::LSB; } -void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { +void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer,TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ) { + // No way to activate correctly the roger beep in this option, Maybe not enough M4 CPU power , Let's block roger beep in SSB selection by now . int32_t sample = 0; int8_t re = 0, im = 0; @@ -55,7 +86,9 @@ void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { float i = 0.0, q = 0.0; sample = audio.p[counter / over] >> 2; - //switch (mode) { + sample *= audio_gain; // Apply GAIN Scale factor to the audio TX modulation. + + //switch (mode) { //case Mode::LSB: hilbert.execute(sample / 32768.0f, i, q); //case Mode::USB: hilbert.execute(sample / 32768.0f, q, i); @@ -72,9 +105,23 @@ void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { //re = q; //im = i; //break; + } buffer.p[counter] = { re, im }; + + // Update vu-meter bar in the LCD screen. + power_acc += (sample < 0) ? -sample : sample; // Power average for UI vu-meter + + if (new_power_acc_count) { + new_power_acc_count--; + } else { // power_acc_count = 0 + new_power_acc_count = new_divider; + new_level_message.value = power_acc / (new_divider *8); // Why ? . This division is to adj vu-meter sentitivity, to match saturation point to red-muter . + shared_memory.application_queue.push(new_level_message); + power_acc = 0; + } + } } @@ -88,15 +135,39 @@ void FM::set_fm_delta(uint32_t new_delta) { fm_delta = new_delta; } -void FM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { +void FM::set_tone_gen_configure(const uint32_t set_delta, const float set_tone_mix_weight) { + tone_gen.configure(set_delta, set_tone_mix_weight); +} + +void FM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ) { int32_t sample = 0; int8_t re, im; for (size_t counter = 0; counter < buffer.count; counter++) { - if (counter % over == 0) { - sample = audio.p[counter / over] >> 8; - delta = sample * fm_delta; - } + + sample = audio.p[counter>>6] >> 8; // sample = audio.p[counter / over] >> 8; (not enough efficient running code, over = 1536000/240000= 64 ) + sample *= audio_gain; // Apply GAIN Scale factor to the audio TX modulation. + + if (play_beep) { + sample = apply_beep(sample, configured_in, new_beep_index, new_beep_timer, new_txprogress_message ); // Apply beep -if selected - atom ,sample by sample. + } else { + // Update vu-meter bar in the LCD screen. + power_acc += (sample < 0) ? -sample : sample; // Power average for UI vu-meter + + if (new_power_acc_count) { + new_power_acc_count--; + } else { // power_acc_count = 0 + new_power_acc_count = new_divider; + new_level_message.value = power_acc / (new_divider / 4); // Why ? . This division is to adj vu-meter sentitivity, to match saturation point to red-muter . + shared_memory.application_queue.push(new_level_message); + power_acc = 0; + } + // TODO: pending to optimize CPU running code. + // So far , we can not handle all 3 issues at the same time (vu-meter , CTCSS, beep). + sample = tone_gen.process(sample); // Add selected Key_Tone or CTCSS subtone , atom function() , sample by sample. + } + + delta = sample * fm_delta; // Modulate FM phase += delta; sphase = phase >> 24; @@ -112,16 +183,33 @@ AM::AM() { mode = Mode::AM; } -void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) { +void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ) { int32_t sample = 0; int8_t re = 0, im = 0; - float q = 0.0; + float q = 0.0; for (size_t counter = 0; counter < buffer.count; counter++) { if (counter % 128 == 0) { sample = audio.p[counter / over] >> 2; + sample *= audio_gain; // Apply GAIN Scale factor to the audio TX modulation. } + if (play_beep) { + sample = apply_beep(sample, configured_in, new_beep_index, new_beep_timer, new_txprogress_message )<<5; // Apply beep -if selected - atom sample by sample. + } else { + // Update vu-meter bar in the LCD screen. + power_acc += (sample < 0) ? -sample : sample; // Power average for UI vu-meter + + if (new_power_acc_count) { + new_power_acc_count--; + } else { // power_acc_count = 0 + new_power_acc_count = new_divider; + new_level_message.value = power_acc / (new_divider *8); // Why ?orig / (new_divider / 4); // Why ? + shared_memory.application_queue.push(new_level_message); + power_acc = 0; + } + } + q = sample / 32768.0f; q *= 256.0f; // Original 64.0f,now x4 (+12 dB's BB_modulation in AM & DSB) switch (mode) { diff --git a/firmware/baseband/dsp_modulate.hpp b/firmware/baseband/dsp_modulate.hpp index fdc6e95f..de964a68 100644 --- a/firmware/baseband/dsp_modulate.hpp +++ b/firmware/baseband/dsp_modulate.hpp @@ -24,6 +24,8 @@ #include "dsp_types.hpp" #include "dsp_hilbert.hpp" +#include "tone_gen.hpp" +#include "baseband_processor.hpp" namespace dsp { namespace modulate { @@ -41,13 +43,28 @@ enum class Mode { class Modulator { public: - virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) = 0; + virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer,bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ) = 0; virtual ~Modulator(); Mode get_mode(); void set_mode(Mode new_mode); void set_over(uint32_t new_over); + void set_gain_vumeter_beep(float new_audio_gain , bool new_play_beep ); + int32_t apply_beep(int32_t sample_in, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message ); + float audio_gain { }; + bool play_beep { false }; + uint32_t power_acc_count { 0 }; // this var it is initialized from Proc_mictx.cpp + uint32_t divider { }; // this var it is initialized from Proc_mictx.cpp + uint64_t power_acc { 0 }; // it is aux Accumulated sum (Absolute sample signal) , initialitzed to zero. + AudioLevelReportMessage level_message { }; + +private: + static constexpr size_t baseband_fs = 1536000U; + TXProgressMessage txprogress_message { }; + ToneGen beep_gen { }; + uint32_t beep_index { }, beep_timer { }; + protected: uint32_t over = 1; @@ -60,7 +77,7 @@ class SSB : public Modulator { public: SSB(); - virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer); + virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ); private: dsp::HilbertTransform hilbert; @@ -72,8 +89,9 @@ class FM : public Modulator { public: FM(); - virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer); + virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ) ; void set_fm_delta(uint32_t new_delta); + void set_tone_gen_configure(const uint32_t delta, const float tone_mix_weight); /// @@ -81,13 +99,16 @@ private: uint32_t fm_delta { 0 }; uint32_t phase { 0 }, sphase { 0 }; int32_t sample { 0 }, delta { }; + ToneGen tone_gen { }; + + }; class AM : public Modulator { public: AM(); - virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer); + virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& configured_in, uint32_t& new_beep_index, uint32_t& new_beep_timer, TXProgressMessage& new_txprogress_message, AudioLevelReportMessage& new_level_message, uint32_t& new_power_acc_count, uint32_t& new_divider ); }; } /* namespace modulate */ diff --git a/firmware/baseband/proc_mictx.cpp b/firmware/baseband/proc_mictx.cpp index d5c0040c..6c9c9b97 100644 --- a/firmware/baseband/proc_mictx.cpp +++ b/firmware/baseband/proc_mictx.cpp @@ -35,8 +35,10 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){ if (!configured) return; audio_input.read_audio_buffer(audio_buffer); - modulator->execute(audio_buffer, buffer); - + modulator->set_gain_vumeter_beep(audio_gain, play_beep ) ; + modulator->execute(audio_buffer, buffer, configured, beep_index, beep_timer, txprogress_message, level_message, power_acc_count, divider ); // Now "Key Tones & CTCSS" baseband additon inside FM mod. dsp_modulate.cpp" + + /* Original fw 1.3.1 good reference, beep and vu-meter for (size_t i = 0; i < buffer.count; i++) { if (!play_beep) { @@ -67,13 +69,13 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){ beep_index++; } } - - sample = beep_gen.process(0); - } - - /* + sample = beep_gen.process(0); // TODO : Pending how to move inside modulate.cpp + } + */ + + /* Original fw 1.3.1 good reference FM moulation version, including "key tones CTCSS" fw 1.3.1 sample = tone_gen.process(sample); - + // FM if (configured) { delta = sample * fm_delta; @@ -89,8 +91,8 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){ } buffer.p[i] = { re, im }; - */ - } + + } */ } void MicTXProcessor::on_message(const Message* const msg) { @@ -100,12 +102,16 @@ void MicTXProcessor::on_message(const Message* const msg) { switch(msg->id) { case Message::ID::AudioTXConfig: if (fm_enabled) { - dsp::modulate::FM *fm = new dsp::modulate::FM(); - - fm->set_fm_delta(config_message.deviation_hz * (0xFFFFFFUL / baseband_fs)); + dsp::modulate::FM *fm = new dsp::modulate::FM(); + + // Config fm_delta private var inside DSP modulate.cpp + fm->set_fm_delta(config_message.deviation_hz * (0xFFFFFFUL / baseband_fs)); + + // Config properly the private tone_gen function parameters inside DSP modulate.cpp + fm->set_tone_gen_configure(config_message.tone_key_delta, config_message.tone_key_mix_weight); modulator = fm; } - + if (usb_enabled) { modulator = new dsp::modulate::SSB(); modulator->set_mode(dsp::modulate::Mode::USB); @@ -124,7 +130,7 @@ void MicTXProcessor::on_message(const Message* const msg) { modulator->set_mode(dsp::modulate::Mode::DSB); } - modulator->set_over(baseband_fs / 24000); + modulator->set_over(baseband_fs / 24000); // Keep no change. am_enabled = config_message.am_enabled; usb_enabled = config_message.usb_enabled; @@ -137,8 +143,9 @@ void MicTXProcessor::on_message(const Message* const msg) { audio_gain = config_message.audio_gain; divider = config_message.divider; power_acc_count = 0; - - tone_gen.configure(config_message.tone_key_delta, config_message.tone_key_mix_weight); + + // now this config moved, in the case Message::ID::AudioTXConfig , only FM case. + // tone_gen.configure(config_message.tone_key_delta, config_message.tone_key_mix_weight); txprogress_message.done = true; diff --git a/firmware/baseband/proc_mictx.hpp b/firmware/baseband/proc_mictx.hpp index b26cae38..175e53c7 100644 --- a/firmware/baseband/proc_mictx.hpp +++ b/firmware/baseband/proc_mictx.hpp @@ -49,8 +49,8 @@ private: }; AudioInput audio_input { }; - ToneGen tone_gen { }; - ToneGen beep_gen { }; + // ToneGen tone_gen { }; moved to dsp_modulate.cpp + // ToneGen beep_gen { }; moved to dsp_modulate.cpp dsp::modulate::Modulator *modulator = NULL ; bool am_enabled { false }; diff --git a/firmware/baseband/tone_gen.cpp b/firmware/baseband/tone_gen.cpp index dd74579d..d015f94f 100644 --- a/firmware/baseband/tone_gen.cpp +++ b/firmware/baseband/tone_gen.cpp @@ -24,14 +24,20 @@ #include "sine_table_int8.hpp" +/* int32_t ToneGen::tone_sine() { + // TODO : Added for Sonde App. We keep it by now , but it needs to be reviewed in Sonde + // Hoepfully we can manage without it , same as previous fw 1.3.1 int32_t tone_sample = sine_table_i8[tone_phase_] * 0x1000000; tone_phase_ += delta_; return tone_sample; } +*/ + int32_t ToneGen::tone_square() { + // TODO : Added for Sonde App. We keep it by now , but it needs to be reviewed in Sonde int32_t tone_sample = 0; if(tone_phase_ < (UINT32_MAX / 2)) { @@ -46,33 +52,66 @@ int32_t ToneGen::tone_square() { return tone_sample; } +/* void ToneGen::configure(const uint32_t delta, const float tone_mix_weight) { + // Confirmed ! It is not working well in the fw 1.4.4 Mic App , CTCSS generation, (but added for Sonde App) + // I Think it should be deleted or modified but not use it as it is in Mic App . + delta_ = (uint8_t) ((delta & 0xFF000000U) >> 24); + delta_ = delta; tone_mix_weight_ = tone_mix_weight; input_mix_weight_ = 1.0 - tone_mix_weight; - current_tone_type_ = sine; } +*/ + + void ToneGen::configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate) { + // TODO : Added for Sonde App. We keep it by now to avoid compile errors, but it needs to be reviewed in Sonde delta_ = (uint8_t) ((freq * sizeof(sine_table_i8)) / sample_rate); tone_mix_weight_ = tone_mix_weight; input_mix_weight_ = 1.0 - tone_mix_weight; current_tone_type_ = tone_type; +} + + + + +// ----Original available core SW code from fw 1.3.1 , Working also well in Mic App CTCSS Gen from fw 1.4.0 onwards + +// Original direct-look-up synthesis algorithm with Fractional delta phase. It is OK +// Delta and Accumulator fase are stored in 32 bits (4 bytes), 1st top byte used as Modulo-256 Sine look-up table [index] +// the lower 3 bytes (24 bits) are used as a Fractional Detla and Accumulator phase, to have very finer Fstep control. + +void ToneGen::configure(const uint32_t delta, const float tone_mix_weight) { + delta_ = delta; + tone_mix_weight_ = tone_mix_weight; + input_mix_weight_ = 1.0 - tone_mix_weight; } int32_t ToneGen::process(const int32_t sample_in) { if (!delta_) return sample_in; - int32_t tone_sample = 0; - - if(current_tone_type_ == sine) { - tone_sample = tone_sine(); - } - else if(current_tone_type_ == square) { - tone_sample = tone_square(); - } + int32_t tone_sample = sine_table_i8[(tone_phase_ & 0xFF000000U) >> 24]; + tone_phase_ += delta_; + + return (sample_in * input_mix_weight_) + (tone_sample * tone_mix_weight_); +} +// ------------------------------------------------------------- + + + +int32_t ToneGen::process_square(const int32_t sample_in) { + // TODO : Added for Sonde App. We keep it by now , but it needs to be reviewed in Sonde + if (!delta_) + return sample_in; + + int32_t tone_sample = 0; + + tone_sample = tone_square(); + return (sample_in * input_mix_weight_) + (tone_sample * tone_mix_weight_); } diff --git a/firmware/baseband/tone_gen.hpp b/firmware/baseband/tone_gen.hpp index c1eee222..eca69e2f 100644 --- a/firmware/baseband/tone_gen.hpp +++ b/firmware/baseband/tone_gen.hpp @@ -28,7 +28,7 @@ class ToneGen { public: - enum tone_type { sine, square }; + enum tone_type { sine, square }; // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. /*ToneGen(const size_t sample_rate ) : sample_rate_ { sample_rate } @@ -38,6 +38,7 @@ public: void configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate); int32_t process(const int32_t sample_in); + int32_t process_square(const int32_t sample_in); private: tone_type current_tone_type_ { sine }; @@ -45,19 +46,23 @@ private: float input_mix_weight_ { 1 }; float tone_mix_weight_ { 0 }; - uint8_t delta_ { 0 }; - uint8_t tone_phase_ { 0 }; + uint32_t delta_ { 0 }; + uint32_t tone_phase_ { 0 }; + +// uint8_t delta_ { 0 }; // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. +// uint8_t tone_phase_ { 0 }; // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. /** * Generator function which selects every other sample from the reference sine waveform to the output sample: */ - int32_t tone_sine(); + int32_t tone_sine();// TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. /** * Generator function for square waves: */ - int32_t tone_square(); + int32_t tone_square(); // TODO: Added for Radio Sonde.cpp PR 376, 381 , we need to check if keep or not. + }; #endif /* __TONE_GEN_H__ */ diff --git a/firmware/common/ak4951.cpp b/firmware/common/ak4951.cpp index 1f88a3d6..74301ecb 100644 --- a/firmware/common/ak4951.cpp +++ b/firmware/common/ak4951.cpp @@ -216,347 +216,90 @@ void AK4951::speaker_disable() { set_speaker_power(false); } -void AK4951::microphone_enable(int8_t alc_mode) { -// alc_mode =0 = (OFF =same as original code = NOT using AK4951 Programmable digital filter block), -// alc_mode >1 (with DIGITAL FILTER BLOCK , example : 1:(+12dB) , 2:(+9dB)", 3:(+6dB), ...) - -// map.r.digital_mic.DMIC = 0; // originally commented code -// update(Register::DigitalMic); // originally commented code - -uint_fast8_t mgain =0b0111; // Pre-amp mic (Original code, =0b0111 (+21dB's=7x3dBs),(Max is NOT 0b1111!, it is 0b1010=+30dBs=10x3dBs) - -map.r.signal_select_2.INL = 0b01; // Lch input signal = LIN2 , our ext. MONO MIC is connected here LIN2 in Portapack. -map.r.signal_select_2.INR = 0b01; // Rch input signal = RIN2 , Not used ,not connected ,but no problem. -map.r.signal_select_2.MICL = 0; // MPWR = 2.4V (it has two possible settings , 2.4V or 2.0V) , (majority smarthphones around 2V , range 1V-5V) -update(Register::SignalSelect2); - -// ------Common code part, = original setting conditions, it is fine for all user-GUI alc_modes: OFF , and ALC modes .*/ -map.r.digital_filter_select_1.HPFAD = 1; // HPF1 ON (after ADC);page 40 datasheet, HPFAD bit controls the ON/OFF of the HPF1 (HPF ON is recommended). -map.r.digital_filter_select_1.HPFC = 0b11; // HPF Cut off frequency of high pass filter from 236.8 Hz @fs=48k ("00":3.7Hz, "01":14,8Hz, "10":118,4Hz) -update(Register::DigitalFilterSelect1); - -// map.r.r_ch_mic_gain_setting.MGR = 0x80; // Microphone sensitivity correction = 0dB., (not used by now , original code cond.) -// update(Register::RchMicGainSetting); // (those two lines , not activated, same as original) - -// pre-load 4 byes LPF coefficicients (.lpf_coefficient_0,1,2,3), FSA 14..0, FSB 14..0 , (fcut initial 6kHz, fs 48Khz). -// it will be default pre-loading coeff. for al ALC modes, LPF bit is activated down, for all ALC digital modes. -map.r.lpf_coefficient_0.l = 0x5F; // Pre-loading here LPF 6kHz, 1st Order from digital Block , Fc=6000 Hz, fs = 48khz -map.r.lpf_coefficient_1.h = 0x09; // LPF bit is activated down, for all ALC digital modes. -map.r.lpf_coefficient_2.l = 0xBF; // Writting reg to AK4951, with "update", following instructions. -map.r.lpf_coefficient_3.h = 0x32; - -update(Register::LPFCoefficient0); // Writing pre-loaded 4 bytes LPF CoefFiecients 14 bits (FSA13..0, FSB13..0 -update(Register::LPFCoefficient1); // In this case , LPF 6KHz , when we activate the LPF block. -update(Register::LPFCoefficient2); -update(Register::LPFCoefficient3); - -// Reset , setting OFF all 5 x Digital Equalizer filters -map.r.digital_filter_select_3.EQ1 = 0; // EQ1 Coeffic Setting , (0: Disable-default, audio data passes EQ1 block by 0dB gain). When EQ1="1”, the settings of E1A15-0, E1B15-0 and E1C15-0 bits are enabled -map.r.digital_filter_select_3.EQ2 = 0; // EQ2 Coeffic Setting , (0: Disable-default, audio data passes EQ2 block by 0dB gain). When EQ2="1”, the settings of E2A15-0, E2B15-0 and E2C15-0 bits are enabled -map.r.digital_filter_select_3.EQ3 = 0; // EQ3 Coeffic Setting , (0: Disable-default, audio data passes EQ3 block by 0dB gain). When EQ3="1”, the settings of E3A15-0, E3B15-0 and E3C15-0 bits are enabled -map.r.digital_filter_select_3.EQ4 = 0; // EQ4 Coeffic Setting , (0: Disable-default, audio data passes EQ4 block by 0dB gain). When EQ4="1”, the settings of E4A15-0, E4B15-0 and E4C15-0 bits are enabled -map.r.digital_filter_select_3.EQ5 = 0; // EQ5 Coeffic Setting , (0: Disable-default, audio data passes EQ5 block by 0dB gain). When EQ5="1”, the settings of E5A15-0, E5B15-0 and E5C15-0 bits are enabled -update(Register::DigitalFilterSelect3); // A,B,C EQ1 Coefficients are already pre-loaded in ak4951.hpp - - - if (alc_mode==0) { // Programmable Digital Filter OFF, same as original condition., no Digital ALC, nor Wind Noise Filter, LPF , EQ - - map.r.digital_filter_select_2.LPF = 0; // LPF-Block, Coeffic Setting Enable (OFF-Default), When LPF bit is “0”, audio data passes the LPF block by 0dB gain. - update(Register::DigitalFilterSelect2); - - // Pre-loading AUDIO PATH with all DIGITAL BLOCK by pased, see, audio path block diagramm AK4951 datasheet + Table Playback mode -Recording mode. - // Digital filter block PATH is BY PASSED (we can swith off DIG. BLOCK power , PMPFIL=0) .The Path in Recording Mode 2 & Playback Mode 2 (NO DIG FILTER BLOCK AT ALL, not for MIC recording, nor for Playback) - map.r.digital_filter_mode.ADCPF = 1; // ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode) - map.r.digital_filter_mode.PFSDO = 0; // ADC bit switch ("0" : 1st order HPF) connectedto the Output. By bass DIGITAL block . - map.r.digital_filter_mode.PFDAC = 0b00; // (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin) - update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode. - - map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal. Mic Amp Lch and ADC Lch Power Management - map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal. Mic Amp Rch and ADC Rch Power Management - map.r.power_management_1.PMPFIL = 0; // Pre-loading , Programmable Dig. filter OFF ,filter unused, routed around.(original value = 0 ) - update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used ) - - // 1059/fs, 22ms @ 48kHz - chThdSleepMilliseconds(22); - - } else { // ( alc_mode !=0) - - switch(alc_mode) { // Pre-loading register values depending on user-GUI selection (they will be sended below, with "update(Register_name::xxx )". - - case 1: // ALC-> on, (+12dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0xC0; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, C0H=+12dBs) - map.r.l_ch_input_volume_control.IV = 0xC0; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xC0; // Right Input Dig Vol Setting, same comment as above , The value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 2: // ALC-> on, (+09dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0xB8; // REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, B8H= +9dBs) - map.r.l_ch_input_volume_control.IV = 0xB8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xB8; // Right Input Dig Vol Setting, same comment as above , The value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 3: // ALC-> on, (+06dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0xB0; // 0xB8 , REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, B0H= +6dBs) - map.r.l_ch_input_volume_control.IV = 0xB0; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xB0; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 4: // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + Pre-amp Mic (+21dB=original) - // + EQ boosting ~<2kHz (f0:1,1k, fb:1,7K, k=1,8) && + LPF 3,5k - map.r.alc_mode_control_2.REF = 0xA8; // 0xA8 , REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A8H= +3dBs) - map.r.l_ch_input_volume_control.IV = 0xA8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xA8; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - //The EQn (n=1, 2, 3, 4 or 5) coefficient must be set when EQn bit = “0” or PMPFIL bit = “0”. - map.r.digital_filter_select_3.EQ1 = 1; // EQ1 Coeffic Setting , (0: Disable-default, audio data passes EQ1 block by 0dB gain). When EQ1="1”, the settings of E1A15-0, E1B15-0 and E1C15-0 bits are enabled - update(Register::DigitalFilterSelect3); // A,B,C EQ1 Coefficients are already pre-loaded in ak4951.hpp - - map.r.lpf_coefficient_0.l = 0x0D; // Pre-loading here LPF 3,5k , 1st Order from digital Block , Fc=3.500 Hz, fs = 48khz - map.r.lpf_coefficient_1.h = 0x06; // LPF bit is activated down, for all ALC digital modes. - map.r.lpf_coefficient_2.l = 0x1A; // Writting reg to AK4951 , down with update.... - map.r.lpf_coefficient_3.h = 0x2C; - // LPF bit is activated down, for all ALC digital modes. - break; - - case 5: // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + Pre-amp Mic (+21dB=original) - // + EQ boosting ~<3kHz (f0~1k4,fb~2,4k,k=1,8) && LPF 4kHz - map.r.alc_mode_control_2.REF = 0xA8; // 0xA0 , REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A8H= +3dBs) - map.r.l_ch_input_volume_control.IV = 0xA8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xA8; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - map.r.digital_filter_select_3.EQ2 = 1; // EQ2 Coeffic Setting , (0: Disable-default, audio data passes EQ2 block by 0dB gain). When EQ2="1”, the settings of E2A15-0, E2B15-0 and E2C15-0 bits are enabled - update(Register::DigitalFilterSelect3); - - map.r.lpf_coefficient_0.l = 0xC3; // Pre-loading here LPF 4k , 1st Order from digital Block , Fc=4000 Hz, fs = 48khz - map.r.lpf_coefficient_1.h = 0x06; // LPF bit is activated down, for all ALC digital modes. - map.r.lpf_coefficient_2.l = 0x86; // Writting reg to AK4951 , down with update.... - map.r.lpf_coefficient_3.h = 0x2D; - // LPF bit is activated down, for all ALC digital modes. - break; - - case 6: // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0xA8; // REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A0H= 0dBs) - map.r.l_ch_input_volume_control.IV = 0xA8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xA8; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 7: // ALC-> on, (+00dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0xA0; // REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A0H= 0dBs) - map.r.l_ch_input_volume_control.IV = 0xA0; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0xA0; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 8: // ALC-> on, (-03dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0x98; //REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 98H=-03dBs) - map.r.l_ch_input_volume_control.IV = 0x98; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0x98; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s +void AK4951::microphone_enable() { +// map.r.digital_mic.DMIC = 0; +// update(Register::DigitalMic); - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; + const uint_fast8_t mgain = 0b0111; + map.r.signal_select_1.MGAIN20 = mgain & 7; + map.r.signal_select_1.PMMP = 1; + map.r.signal_select_1.MPSEL = 1; // MPWR2 pin + map.r.signal_select_1.MGAIN3 = (mgain >> 3) & 1; + update(Register::SignalSelect1); - case 9: // ALC-> on, (-06dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) - map.r.alc_mode_control_2.REF = 0x90; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 90H=-06dBs) - map.r.l_ch_input_volume_control.IV = 0x90; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0x90; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s + map.r.signal_select_2.INL = 0b01; // Lch input signal = LIN2 + map.r.signal_select_2.INR = 0b01; // Rch input signal = RIN2 + map.r.signal_select_2.MICL = 0; // MPWR = 2.4V + update(Register::SignalSelect2); - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 10: // ALC-> on, (-09dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz - Pre-amp MIC -3dB (18dB's) - // Reduce also Pre-amp Mic -3dB's (+18dB's) - mgain = 0b0110; // Pre-amp mic Mic Gain Pre-amp (+18dB), Original=0b0111 (+21dB's =7x3dBs), - - map.r.alc_mode_control_2.REF = 0x88; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 88H=-09dBs) - map.r.l_ch_input_volume_control.IV = 0x88; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0x88; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - - case 11: // ALC-> on, (-12dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz - Pre-amp MIC -6dB (15dB's) - // Reduce also Pre-amp Mic -6dB's (+15dB's) - mgain = 0b0101; // Pre-amp mic Mic Gain Pre-amp (+15dB), (Original=0b0111 (+21dB's= 7x3dBs), - - map.r.alc_mode_control_2.REF = 0x80; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 80H=-12dBs) - map.r.l_ch_input_volume_control.IV = 0x80; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - map.r.r_ch_input_volume_control.IV = 0x80; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REF’s - - // Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz - // LPF bit is activated down, for all ALC digital modes. - break; - } - - //-------------------------------DIGITAL ALC (Automatic Level Control ) --- -------- - map.r.alc_mode_control_1.ALC = 0; // LMTH2-0, WTM1-0, RGAIN2-0, REF7-0, RFST1-0, EQFC1-0, FRATT, FRN and ALCEQN bits (needs to be set up with ALC disable = 0) - update(Register::ALCModeControl1); - - map.r.timer_select.FRN = 0; // (FRN= 0 Fast Recovery mode , enable ) - map.r.timer_select.FRATT = 0; // Fast Recovery Ref. Volume Atten. Amount -0,00106dB's, timing 4/fs (default) - map.r.timer_select.ADRST = 0b00; // initial offset ADC cycles , 22ms @fs=48Khz. +// map.r.r_ch_mic_gain_setting.MGR = 0x80; // Microphone sensitivity correction = 0dB. +// update(Register::RchMicGainSetting); +/* + map.r.timer_select.FRN = ?; + map.r.timer_select.FRATT = ?; + map.r.timer_select.ADRST = 0b??; update(Register::TimerSelect); - map.r.alc_timer_select.RFST = 0b00; // RFST1-0: ALC Fast Recovery Speed Default: “00” (0.0032dB) - map.r.alc_timer_select.WTM = 0b00; // ALC Recovery Operation Waiting Period 128/fs = 2,7 mseg (min=default) - map.r.alc_timer_select.EQFC = 0b10; // Selecting default, fs 48Khz , ALCEQ: First order zero pole high pass filter fc2=100Hz, fc1=150Hz - map.r.alc_timer_select.IVTM = 0; // IVTM bit set the vol transition time ,236/fs = 4,9msecs (min) (default was 19,7msegs.) + map.r.alc_timer_select. = ?; update(Register::ALCTimerSelect); - - map.r.alc_mode_control_1.LMTH10 = 0b11; // ALC Limiter Detec Level/ Recovery Counter Reset; lower 2 bits (Ob111=-8,4dbs), (default 0b000=-2,5dBs) - map.r.alc_mode_control_1.RGAIN = 0b000; // ALC Recovery Gain Step, max step , max speed. Default: “000” (0.00424dB) - map.r.alc_mode_control_1.ALC = 1; // ALC Enable . (we are now, NOT in MANUAL volume mode, only becomes manual when (ALC=“0” while ADCPF=“1”. ) - map.r.alc_mode_control_1.LMTH2 = 1; // ALC Limiter Detection Level/ Recovery Counter Reset Level,Upper bit,default 0b000 - map.r.alc_mode_control_1.ALCEQN = 1; // ALC EQ Off =1 not used by now, 0: ALC EQ On (default) + map.r.alc_mode_control_1. = ?; + map.r.alc_mode_control_1.ALC = 1; update(Register::ALCModeControl1); - // map.r.alc_mode_control_2.REF = 0x??; // Pre-loaded in top part. Maximum gain at ALC recovery operation,.(FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) + map.r.alc_mode_control_2.REF = ?; update(Register::ALCModeControl2); - - // map.r.l_ch_input_volume_control.IV = 0x??; // Pre-loaded in top part. Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - update(Register::LchInputVolumeControl); - - // map.r.r_ch_input_volume_control.IV = 0x??; // Pre-loaded in top part. Right,Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs) - update(Register::RchInputVolumeControl); - - - //---------------Switch ON, Digital Automatic Wind Noise Filter reduction ------------------- - // Difficult to realise that Dynamic HPF Wind noise filter benefit, maybe because we have another fixed HPF 236.8 Hz . - // Anyway , we propose to activate it , with default setting conditions. - map.r.power_management_1.PMPFIL = 0; // (*1) To programm SENC, STG , we need PMPFIL = 0 . (but this disconnect Digital block power supply. - update(Register::PowerManagement1); // Updated PMPFIL to 0 . (*1) - - map.r.auto_hpf_control.STG = 0b00; // (00=LOW ATTENUATION Level), lets put 11 (HIGH ATTENUATION Level) (default 00) - map.r.auto_hpf_control.SENC = 0b011; // (000=LOW sensitivity detection)… 111((MAX sensitivity detection) (default 011) - map.r.auto_hpf_control.AHPF = 1; // Autom. Wind noise filter ON (AHPF bit=“1”).It atten. wind noise when detecting ,and adjusts the atten. level dynamically. - update(Register::AutoHPFControl); - - // We are in Digital Block ON , (Wind Noise Filter+ALC+LPF+EQ),==> needs at the end , PMPFIL=1 , Program. Dig.filter ON - // map.r.power_management_1.PMPFIL = 1; // that instruction is at the end , we can skp pre-loading Programmable Dig. filter ON (*1) - //--------------------------------------------------------------------- - - // Writing AUDIO PATH diagramm, Changing Audio mode path : Playback mode1 /-Recording mode2. (Figure 37 AK4951 datasheet, Table 27. Recording Playback Mode) - // When changing those modes, PMPFIL bit must be “0”, it is OK (*1) - map.r.digital_filter_mode.ADCPF = 1; // ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode) - map.r.digital_filter_mode.PFSDO = 1; // ADC (+ 1st order HPF) Output - map.r.digital_filter_mode.PFDAC = 0b00; // (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin) - update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode. - - // The EQn (n=1, 2, 3, 4 or 5) coefficient must be set when EQn bit = “0” or PMPFIL bit = “0”., but we are already (*1) - // map.r.power_management_1.PMPFIL = 0; // In the previous Wind Noise Filter , we already set up PPFIL = 0 - // update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used ) - - // ... Set EQ & LPF coefficients --------------------------------- - - // writting to the IC ak4951 reg. settings defined in Ak4951.hpp , the 30 bytes , EQ coefficient = 5 (EQ1,2,3,4,5) x 3 (A,B,C coefficients) x 2 bytes (16 bits) - update(Register::E1Coefficient0); // we could pre-load here,ex ,"map.r.e1_coefficient_0.l = 0x50;" , EQ1 Coefficient A : A7...A0, but already done in ak4951.hpp - update(Register::E1Coefficient1); // we could pre-load here,ex ,"map.r.e1_coefficient_1.h = 0xFE;" , EQ1 Coefficient A : A15..A8, " " - update(Register::E1Coefficient2); // we could pre-load here,ex ,"map.r.e1_coefficient_2.l = 0x29;" , EQ1 Coefficient B : B7...B0, " " - update(Register::E1Coefficient3); // we could pre-load here,ex ,"map.r.e1_coefficient_3.h = 0xC5;" , EQ1 Coefficient B : B15..B8, " " - update(Register::E1Coefficient4); // we could pre-load here,ex ,"map.r.e1_coefficient_4.l = 0xA0;" , EQ1 Coefficient C : C7...C0, " " - update(Register::E1Coefficient5); // we could pre-load here,ex ,"map.r.e1_coefficient_5.h = 0x1C;" , EQ1 Coefficient C : C15..C8, " " - - update(Register::E2Coefficient0); // writing pre-loaded EQ2 coefficcients - update(Register::E2Coefficient1); - update(Register::E2Coefficient2); - update(Register::E2Coefficient3); - update(Register::E2Coefficient4); - update(Register::E2Coefficient5); - - // Already pre-loaded LPF coefficients to 6k, 3,5k or 4k ,(LPF 6Khz all digital alc modes top , except when 3k5 , 4k) - update(Register::LPFCoefficient0); // Writing pre-loaded 4 bytes LPF CoefFiecients 14 bits (FSA13..0, FSB13..0 - update(Register::LPFCoefficient1); - update(Register::LPFCoefficient2); - update(Register::LPFCoefficient3); - - // Activating LPF block , (and re-configuring the rest of bits of the same register) - map.r.digital_filter_select_2.HPF = 0; // HPF2-Block, Coeffic Setting Enable (OFF-Default), When HPF bit is “0”, audio data passes the HPF2 block by is 0dB gain. - map.r.digital_filter_select_2.LPF = 1; // LPF-Block, Coeffic Setting Enable (OFF-Default), When LPF bit is “0”, audio data passes the LPF block by 0dB gain. - map.r.digital_filter_select_2.FIL3 = 0; // Stereo_Emphasis_Filter-Block,(OFF-Default) Coefficient Setting Enable , OFF , Disable. - map.r.digital_filter_select_2.EQ0 = 0; // Gain Compensation-Block, (OFF-Default) Coeffic Setting Enable, When EQ0 bit = “0” audio data passes the EQ0 block by 0dB gain. - map.r.digital_filter_select_2.GN = 0b00; // Gain Setting of the Gain Compensation Block Default: “00”-Default (0dB) +*/ +// map.r.l_ch_input_volume_control.IV = 0xe1; +// update(Register::LchInputVolumeControl); +// map.r.r_ch_input_volume_control.IV = 0xe1; +// update(Register::RchInputVolumeControl); +/* + map.r.auto_hpf_control.STG = 0b00; + map.r.auto_hpf_control.SENC = 0b011; + map.r.auto_hpf_control.AHPF = 0; + update(Register::AutoHPFControl); +*/ + map.r.digital_filter_select_1.HPFAD = 1; // HPF1 (after ADC) = on + map.r.digital_filter_select_1.HPFC = 0b11; // 2336.8 Hz @ fs=48k + update(Register::DigitalFilterSelect1); +/* + map.r.digital_filter_select_2.HPF = 0; + map.r.digital_filter_select_2.LPF = 0; + map.r.digital_filter_select_2.FIL3 = 0; + map.r.digital_filter_select_2.EQ0 = 0; + map.r.digital_filter_select_2.GN = 0b00; update(Register::DigitalFilterSelect2); - // Acitivating digital block , power supply - map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal. Mic Amp Lch and ADC Lch Power Management - map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal. Mic Amp Rch and ADC Rch Power Management - map.r.power_management_1.PMPFIL = 1; // Pre-loaded in top part. Orig value=0, Programmable Digital filter unused (not power up), routed around. - update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used ) + map.r.digital_filter_select_3.EQ1 = 0; + map.r.digital_filter_select_3.EQ2 = 0; + map.r.digital_filter_select_3.EQ3 = 0; + map.r.digital_filter_select_3.EQ4 = 0; + map.r.digital_filter_select_3.EQ5 = 0; + update(Register::DigitalFilterSelect3); +*/ + map.r.digital_filter_mode.PFSDO = 0; // ADC (+ 1st order HPF) Output + map.r.digital_filter_mode.ADCPF = 1; // ADC Output (default) + update(Register::DigitalFilterMode); + + // ... Set coefficients ... + + map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal + map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal + map.r.power_management_1.PMPFIL = 0; // Programmable filter unused, routed around. + update(Register::PowerManagement1); // 1059/fs, 22ms @ 48kHz chThdSleepMilliseconds(22); - - } - - // Common part for all alc_mode , -------------------------- - // const uint_fast8_t mgain = 0b0111; // Already pre-loaded , in above switch case . - map.r.signal_select_1.MGAIN20 = mgain & 7; // writing 3 lower bits of mgain , (pre-amp mic gain). - map.r.signal_select_1.PMMP = 1; // Activating DC Mic Power supply through 2kohms res., similar majority smartphones headphone+mic jack, "plug-in-power" - map.r.signal_select_1.MPSEL = 1; // MPWR2 pin ,selecting output voltage to MPWR2 pin, that we are using in portapack ext. MIC) - map.r.signal_select_1.MGAIN3 = (mgain >> 3) & 1; // writing 4th upper bit of mgain (pre-amp mic gain). - update(Register::SignalSelect1); - } - - void AK4951::microphone_disable() { - map.r.power_management_1.PMADL = 0; // original code , disable Power managem.Mic ADC L - map.r.power_management_1.PMADR = 0; // original code , disable Power managem.Mic ADC R - map.r.power_management_1.PMPFIL = 0; // original code , disable Power managem. all Programmable Dig. block + map.r.power_management_1.PMADL = 0; + map.r.power_management_1.PMADR = 0; + map.r.power_management_1.PMPFIL = 0; update(Register::PowerManagement1); - map.r.alc_mode_control_1.ALC = 0; // original code , Restore , disable ALC block. + map.r.alc_mode_control_1.ALC = 0; update(Register::ALCModeControl1); - - map.r.auto_hpf_control.AHPF = 0; //----------- new code addition , Restore disable Wind noise filter OFF (AHPF bit=“0”). - update(Register::AutoHPFControl); - - //Restore original AUDIO PATH , condition, (Digital filter block PATH is BY PASSED) (we can also swith off DIG. BLOCK power , PMPFIL=0) - // The Path in Recording Mode 2 & Playback Mode 2 , (NO DIG FILTER BLOCK AT ALL, not for MIC recording, nor for Playback) - map.r.digital_filter_mode.ADCPF = 1; // new code addition , ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode) - map.r.digital_filter_mode.PFSDO = 0; // new code addition , ADC bit switch ("0" : 1st order HPF) connectedto the Output. By bass DIGITAL block . - map.r.digital_filter_mode.PFDAC = 0b00; // new code addition , (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin) - update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode. - - // Restore original condition , LPF , OFF . same as when not using DIGITAL Programmable block - map.r.digital_filter_select_2.LPF = 0; // LPF-Block, Coeffic Setting Enable (OFF-Default), When LPF bit is “0”, audio data passes the LPF block by 0dB gain. - update(Register::DigitalFilterSelect2); - - map.r.lpf_coefficient_0.l = 0x00; // Pre-loading here LPF 6k , 1st Order from digital Block , Fc=6000 Hz, fs = 48khz - map.r.lpf_coefficient_1.h = 0x00; // LPF bit is activated down, for all ALC digital modes. - map.r.lpf_coefficient_2.l = 0x00; // Writting reg to AK4951 , down with update.... - map.r.lpf_coefficient_3.h = 0x00; - - update(Register::LPFCoefficient0); // Writing pre-loaded 4 bytes LPF CoefFiecients 14 bits (FSA13..0, FSB13..0 - update(Register::LPFCoefficient1); - update(Register::LPFCoefficient2); - update(Register::LPFCoefficient3); - - // Switch off all EQ 1,2,3,4,5 - map.r.digital_filter_select_3.EQ1 = 0; // EQ1 Coeffic Setting , (0: Disable-default, audio data passes EQ1 block by 0dB gain). When EQ1="1”, the settings of E1A15-0, E1B15-0 and E1C15-0 bits are enabled - map.r.digital_filter_select_3.EQ2 = 0; // EQ2 Coeffic Setting , (0: Disable-default, audio data passes EQ2 block by 0dB gain). When EQ2="1”, the settings of E2A15-0, E2B15-0 and E2C15-0 bits are enabled - map.r.digital_filter_select_3.EQ3 = 0; // EQ3 Coeffic Setting , (0: Disable-default, audio data passes EQ3 block by 0dB gain). When EQ3="1”, the settings of E3A15-0, E3B15-0 and E3C15-0 bits are enabled - map.r.digital_filter_select_3.EQ4 = 0; // EQ4 Coeffic Setting , (0: Disable-default, audio data passes EQ4 block by 0dB gain). When EQ4="1”, the settings of E4A15-0, E4B15-0 and E4C15-0 bits are enabled - map.r.digital_filter_select_3.EQ5 = 0; // EQ5 Coeffic Setting , (0: Disable-default, audio data passes EQ5 block by 0dB gain). When EQ5="1”, the settings of E5A15-0, E5B15-0 and E5C15-0 bits are enabled - update(Register::DigitalFilterSelect3); - } reg_t AK4951::read(const address_t reg_address) { diff --git a/firmware/common/ak4951.hpp b/firmware/common/ak4951.hpp index 3b1f9e1a..df168a09 100644 --- a/firmware/common/ak4951.hpp +++ b/firmware/common/ak4951.hpp @@ -773,41 +773,40 @@ constexpr RegisterMap default_after_reset { Register_Type { .REV = 0b1100, }, - // just pre-loading into memory, 30 bytes = EQ 1,2,3,4,5 x A,B,C (2 x bytes) coefficients, but it will be written from ak4951.cpp - .e1_coefficient_0 = { .l = 0xCA }, //EQ1 Coefficient A : A7...A0, BW : 300Hz - 1700Hz (fo = 1150Hz , fb= 1700Hz) , k=1,8 peaking - .e1_coefficient_1 = { .h = 0x05 }, //EQ1 Coefficient A : A15..A8 - .e1_coefficient_2 = { .l = 0xEB }, //EQ1 Coefficient B : B7...B0 - .e1_coefficient_3 = { .h = 0x38 }, //EQ1 Coefficient B : B15...B8 - .e1_coefficient_4 = { .l = 0x6F }, //EQ1 Coefficient C : C7...C0 - .e1_coefficient_5 = { .h = 0xE6 }, //EQ1 Coefficient C : C15..C8 + .e1_coefficient_0 = { .l = 0x00 }, + .e1_coefficient_1 = { .h = 0x00 }, + .e1_coefficient_2 = { .l = 0x00 }, + .e1_coefficient_3 = { .h = 0x00 }, + .e1_coefficient_4 = { .l = 0x00 }, + .e1_coefficient_5 = { .h = 0x00 }, - .e2_coefficient_0 = { .l = 0x05 }, //EQ2 Coefficient A : A7...A0, BW : 250Hz - 2700Hz (fo = 1475Hz , fb= 2450Hz) , k=1,8 peaking - .e2_coefficient_1 = { .h = 0x08 }, //EQ2 Coefficient A : A15..A8 - .e2_coefficient_2 = { .l = 0x11 }, //EQ2 Coefficient B : B7...B0 - .e2_coefficient_3 = { .h = 0x36 }, //EQ2 Coefficient B : B15...B8 - .e2_coefficient_4 = { .l = 0xE9 }, //EQ2 Coefficient C : C7...C0 - .e2_coefficient_5 = { .h = 0xE8 }, //EQ2 Coefficient C : C15..C8 + .e2_coefficient_0 = { .l = 0x00 }, + .e2_coefficient_1 = { .h = 0x00 }, + .e2_coefficient_2 = { .l = 0x00 }, + .e2_coefficient_3 = { .h = 0x00 }, + .e2_coefficient_4 = { .l = 0x00 }, + .e2_coefficient_5 = { .h = 0x00 }, - .e3_coefficient_0 = { .l = 0x00 }, //EQ3 Coefficient A : A7...A0, not used currently - .e3_coefficient_1 = { .h = 0x00 }, //EQ3 Coefficient A : A15..A8 - .e3_coefficient_2 = { .l = 0x00 }, //EQ3 Coefficient B : B7...B0 - .e3_coefficient_3 = { .h = 0x00 }, //EQ3 Coefficient B : B15...B8 - .e3_coefficient_4 = { .l = 0x00 }, //EQ3 Coefficient C : C7...C0 - .e3_coefficient_5 = { .h = 0x00 }, //EQ3 Coefficient C : C15..C8 + .e3_coefficient_0 = { .l = 0x00 }, + .e3_coefficient_1 = { .h = 0x00 }, + .e3_coefficient_2 = { .l = 0x00 }, + .e3_coefficient_3 = { .h = 0x00 }, + .e3_coefficient_4 = { .l = 0x00 }, + .e3_coefficient_5 = { .h = 0x00 }, - .e4_coefficient_0 = { .l = 0x00 }, //EQ4 Coefficient A : A7...A0, not used currently - .e4_coefficient_1 = { .h = 0x00 }, //EQ4 Coefficient A : A15..A8 - .e4_coefficient_2 = { .l = 0x00 }, //EQ4 Coefficient B : B7...B0 - .e4_coefficient_3 = { .h = 0x00 }, //EQ4 Coefficient B : B15...B8 - .e4_coefficient_4 = { .l = 0x00 }, //EQ4 Coefficient C : C7...C0 - .e4_coefficient_5 = { .h = 0x00 }, //EQ4 Coefficient C : C15..C8 + .e4_coefficient_0 = { .l = 0x00 }, + .e4_coefficient_1 = { .h = 0x00 }, + .e4_coefficient_2 = { .l = 0x00 }, + .e4_coefficient_3 = { .h = 0x00 }, + .e4_coefficient_4 = { .l = 0x00 }, + .e4_coefficient_5 = { .h = 0x00 }, - .e5_coefficient_0 = { .l = 0x00 }, //EQ5 Coefficient A : A7...A0, not used currently - .e5_coefficient_1 = { .h = 0x00 }, //EQ5 Coefficient A : A15..A8 - .e5_coefficient_2 = { .l = 0x00 }, //EQ5 Coefficient B : B7...B0 - .e5_coefficient_3 = { .h = 0x00 }, //EQ5 Coefficient B : B15...B8 - .e5_coefficient_4 = { .l = 0x00 }, //EQ5 Coefficient C : C7...C0 - .e5_coefficient_5 = { .h = 0x00 }, //EQ5 Coefficient C : C15..C8 + .e5_coefficient_0 = { .l = 0x00 }, + .e5_coefficient_1 = { .h = 0x00 }, + .e5_coefficient_2 = { .l = 0x00 }, + .e5_coefficient_3 = { .h = 0x00 }, + .e5_coefficient_4 = { .l = 0x00 }, + .e5_coefficient_5 = { .h = 0x00 }, } }; class AK4951 : public audio::Codec { @@ -842,7 +841,7 @@ public: void set_headphone_volume(const volume_t volume) override; void headphone_mute(); - void microphone_enable(int8_t alc_mode); // added user GUI parameter , to set up AK4951 ALC mode. + void microphone_enable(); void microphone_disable(); size_t reg_count() const override { diff --git a/firmware/common/wm8731.hpp b/firmware/common/wm8731.hpp index ac164a04..a5c8908b 100644 --- a/firmware/common/wm8731.hpp +++ b/firmware/common/wm8731.hpp @@ -345,9 +345,8 @@ public: void speaker_disable() {}; - void microphone_enable(int8_t alc_mode) override { - (void)alc_mode; // to avoid "unused warning" when compiling. (@WM8731 we do not use that parameter) - // TODO: Implement, + void microphone_enable() override { + // TODO: Implement } void microphone_disable() override {