diff --git a/firmware/application/apps/soundboard_app.cpp b/firmware/application/apps/soundboard_app.cpp index 02039ae3..344afd35 100644 --- a/firmware/application/apps/soundboard_app.cpp +++ b/firmware/application/apps/soundboard_app.cpp @@ -111,6 +111,7 @@ void SoundBoardView::start_tx(const uint32_t id) { 1536000 / 20, // Update vu-meter at 20Hz transmitter_model.channel_bandwidth(), 0, // Gain is unused + 8, // shift_bits_s16, default 8 bits, but also unused TONES_F2D(tone_key_frequency(tone_key_index), 1536000), 0, //AM 0, //DSB diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index 397b595b..ef8a4cf6 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -74,6 +74,7 @@ void MicTXView::configure_baseband() { sampling_rate / 20, // Update vu-meter at 20Hz transmitting ? transmitter_model.channel_bandwidth() : 0, mic_gain, + shift_bits_s16, // to be used in dsp_modulate TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate), enable_am, enable_dsb, @@ -188,7 +189,7 @@ void MicTXView::rxaudio(bool is_on) { baseband::run_image(portapack::spi_flash::image_tag_mic_tx); audio::output::stop(); - audio::input::start(); // set up audio input = mic config of any audio coded AK4951/WM8731, (in WM8731 parameter will be ignored) + audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // When detected AK4951 => set up ALC mode; when detected WM8731 => set up mic_boost ON/OFF. portapack::pin_i2s0_rx_sda.mode(3); configure_baseband(); } @@ -213,12 +214,12 @@ MicTXView::MicTXView( baseband::run_image(portapack::spi_flash::image_tag_mic_tx); - - 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() ) { + if (audio::debug::codec_name() =="WM8731" ) { add_children({ &labels_WM8731, // we have audio codec WM8731, same MIC menu as original. &vumeter, &options_gain, // MIC GAIN float factor on the GUI. + &options_wm8731_boost_mode, // &check_va, &field_va, &field_va_level, @@ -283,13 +284,43 @@ MicTXView::MicTXView( mic_gain = v / 10.0; configure_baseband(); }; - options_gain.set_selected_index(1); // x1.0 + options_gain.set_selected_index(1); // x1.0 preselected default. + + if (audio::debug::codec_name() =="WM8731") { + options_wm8731_boost_mode.on_change = [this](size_t, int8_t v) { + + switch(v) { + case 0: // +12 dB’s respect reference level orig fw 1.5.x fw FM : when +20dB's boost ON) and shift bits (>>8), + shift_bits_s16 = 6; // now mic-boost on (+20dBs) and shift bits (>>6), +20+12=32 dB’s (orig fw +20 dBs+ 0dBs)=> +12dB's respect ref. + break; + case 1: // +06 dB’s reference level , (when +20dB's boost ON) + shift_bits_s16 = 7; // now mic-boost on (+20dBs) and shift bits (>>7), +20+06=26 dB’s (orig fw +20 dBs+ 0dBs) => +06dB's respect ref. + break; + case 2: + shift_bits_s16 = 4; // +04 dB’s respect ref level , (when +20dB's boost OFF) + break; // now mic-boost off (+00dBs) shift bits (4) (+0+24dB's)=24 dBs => +04dB's respect ref. + case 3: + shift_bits_s16 = 5; // -02 dB’s respect ref level , (when +20dB's boost OFF) + break; // now mic-boost off (+00dBs) shift bits (5) (+0+18dB's)=18 dBs => -02dB's respect ref. + case 4: + shift_bits_s16 = 6; // -08 dB’s respect ref level , (when +20dB's boost OFF) + break; // now mic-boost off (+00dBs) shift bits (6) (+0+12dB's)=12 dBs => -08dB's respect ref. + } + ak4951_alc_and_wm8731_boost_GUI = v; // 0,..4 WM8731_boost dB's options, (combination boost on/off , and effective gain in captured data >>x) + audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // Detected (WM8731) , set up the proper wm_boost on/off , 0..4 (0,1) boost_on , (2,3,4) boost_0ff + configure_baseband(); // to update in real timme,sending msg , var-parameters >>shift_bits FM msg ,to audio_tx from M0 to M4 Proc - + }; + options_wm8731_boost_mode.set_selected_index(3); // preset GUI index 3 as default WM -> -02 dB's . + } else { + shift_bits_s16 = 8; // Initialized default fixed >>8_FM for FM tx mod , shift audio data for AK4951 ,using top 8 bits s16 data (>>8) + options_ak4951_alc_mode.on_change = [this](size_t, int8_t v) { + ak4951_alc_and_wm8731_boost_GUI = v; // 0,..11, AK4951 Mic -Automatic volume Level Control options, + audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // Detected (AK4951) ==> Set up proper ALC mode from 0..11 options + configure_baseband(); // sending fixed >>8_FM , var-parameters msg , to audiotx from this M0 to M4 process. + }; + } - options_ak4951_alc_mode.on_change = [this](size_t, int8_t v) { - ak4951_alc_GUI_selected = v; - audio::input::start(); - }; - // options_ak4951_alc_mode.set_selected_index(0); + // options_ak4951_alc_mode.set_selected_index(0); tx_frequency = transmitter_model.tuning_frequency(); field_frequency.set_value(transmitter_model.tuning_frequency()); @@ -539,9 +570,9 @@ MicTXView::MicTXView( transmitter_model.set_baseband_bandwidth(1750000); set_tx(false); - - audio::set_rate(audio::Rate::Hz_24000); - audio::input::start(); // originally , audio::input::start(); (we added parameter) + + audio::set_rate(audio::Rate::Hz_24000); + audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // When detected AK4951 => set up ALC mode; when detected WM8731 => set up mic_boost ON/OFF. } MicTXView::~MicTXView() { diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp index 9b091e53..be3e397f 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -83,7 +83,7 @@ private: bool rx_enabled { false }; uint32_t tone_key_index { }; float mic_gain { 1.0 }; - uint8_t ak4951_alc_GUI_selected { 0 }; + uint8_t ak4951_alc_and_wm8731_boost_GUI { 0 }; uint32_t audio_level { 0 }; uint32_t va_level { }; uint32_t attack_ms { }; @@ -99,6 +99,7 @@ private: rf::Frequency rx_frequency { 0 }; int32_t focused_ui { 2 }; bool button_touch { false }; + uint8_t shift_bits_s16 {4} ; // shift bits factor to the captured ADC S16 audio sample. //AM TX Stuff bool enable_am { false }; @@ -109,6 +110,7 @@ private: Labels labels_WM8731 { { { 3 * 8, 1 * 8 }, "MIC-GAIN:", Color::light_grey() }, + { { 17 * 8, 1 * 8 }, "Boost", Color::light_grey() }, { { 3 * 8, 3 * 8 }, "F:", Color::light_grey() }, { { 15 * 8, 3 * 8 }, "BW: FM kHz", Color::light_grey() }, { { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() }, @@ -171,7 +173,7 @@ private: { 20 * 8, 1 * 8 }, // Coordinates are: int:x (px), int:y (px) 11, { - { " OFF-20kHz", 0 }, // Nothing changed from ORIGINAL,keeping ALL programm. AK4951 Dig. block->OFF) + { " OFF-12kHz", 0 }, // Nothing changed from ORIGINAL,keeping ALL programmable AK4951 Digital Block->OFF, sampling 24Khz) { "+12dB-6kHz", 1 }, // ALC-> on, (+12dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) { "+09dB-6kHz", 2 }, // ALC-> on, (+09dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) { "+06dB-6kHz", 3 }, // ALC-> on, (+06dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original) @@ -186,6 +188,18 @@ private: } }; +OptionsField options_wm8731_boost_mode { + { 22 * 8, 1 * 8 }, // Coordinates are: int:x (px), int:y (px) + 5, + { + { "ON +12dB", 0 }, // WM8731 Mic Boost ON ,original+12dBs condition, easy to saturate ADC sat in high voice ,relative G = +12 dB's respect ref level + { "ON +06dB", 1 }, // WM8731 Mic Boost ON ,original+6 dBs condition, easy to saturate ADC sat in high voice ,relative G = +06 dB's respect ref level + { "OFF+04dB", 2 }, // WM8731 Mic Boost OFF to avoid ADC sat in high voice ,relative G = +04 dB's (respect ref level) , always effective sampling 24khz + { "OFF-02dB", 3 }, // WM8731 Mic Boost OFF to avoid ADC sat in high voice ,relative G = -02 dB's (respect ref level) + { "OFF-08dB", 4 }, // WM8731 Mic Boost OFF to avoid ADC sat in high voice ,relative G = -12 dB's (respect ref level) + } + }; + FrequencyField field_frequency { { 5 * 8, 3 * 8 }, }; diff --git a/firmware/application/audio.cpp b/firmware/application/audio.cpp index 4ba23acc..ce32076c 100644 --- a/firmware/application/audio.cpp +++ b/firmware/application/audio.cpp @@ -168,8 +168,8 @@ void speaker_mute() { namespace input { -void start() { - audio_codec->microphone_enable(); +void start(int8_t alc_mode) { + audio_codec->microphone_enable(alc_mode); // added user-GUI selection for AK4951, ALC mode parameter. i2s::i2s0::rx_start(); } diff --git a/firmware/application/audio.hpp b/firmware/application/audio.hpp index b02e42aa..56301ee8 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() = 0; + virtual void microphone_enable(int8_t alc_mode) = 0; // added user-GUI AK4951 ,selected ALC mode. virtual void microphone_disable() = 0; virtual size_t reg_count() const = 0; @@ -59,7 +59,7 @@ public: namespace output { -void start(); +void start(); // this other start(),no changed. ,in namespace output , used to config audio playback mode, void stop(); void mute(); @@ -72,7 +72,7 @@ void speaker_unmute(); namespace input { -void start(); +void start(int8_t alc_mode); // added parameter user-GUI select AK4951-ALC mode for config mic path,(recording mode in datasheet), void stop(); } /* namespace input */ diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index 74f472d8..ec7ba1a6 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -183,12 +183,13 @@ void kill_afsk() { } void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain, - const uint32_t tone_key_delta, const bool am_enabled, const bool dsb_enabled, - const bool usb_enabled, const bool lsb_enabled) { + uint8_t audio_shift_bits_s16, const uint32_t tone_key_delta, const bool am_enabled, + const bool dsb_enabled, const bool usb_enabled, const bool lsb_enabled) { const AudioTXConfigMessage message { divider, deviation_hz, audio_gain, + audio_shift_bits_s16, tone_key_delta, (float)persistent_memory::tone_mix() / 100.0f, am_enabled, diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index bcc43375..5c9b3c95 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -61,8 +61,8 @@ void set_tones_config(const uint32_t bw, const uint32_t pre_silence, const uint1 void kill_tone(); void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration); void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain, - const uint32_t tone_key_delta, const bool am_enabled, const bool dsb_enabled, - const bool usb_enabled, const bool lsb_enabled); + uint8_t audio_shift_bits_s16, const uint32_t tone_key_delta, const bool am_enabled, + const bool dsb_enabled, const bool usb_enabled, const bool lsb_enabled); void set_fifo_data(const int8_t * data); void set_pitch_rssi(int32_t avg, bool enabled); void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phase_inc_mark, const uint32_t afsk_phase_inc_space, diff --git a/firmware/baseband/dsp_modulate.cpp b/firmware/baseband/dsp_modulate.cpp index 04102800..34633715 100644 --- a/firmware/baseband/dsp_modulate.cpp +++ b/firmware/baseband/dsp_modulate.cpp @@ -42,10 +42,16 @@ 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 ; +void Modulator::set_gain_shiftbits_vumeter_beep(float new_audio_gain ,uint8_t new_audio_shift_bits_s16, bool new_play_beep ) { + //new_audio_shift_bits_s16 are the direct shift bits (FM mod >>x) , and it is fixed to >>8_FM (AK) or 4,5,6, (WM boost OFF) or 6,7 (WM boost ON) + audio_gain = new_audio_gain ; + audio_shift_bits_s16_FM = new_audio_shift_bits_s16; //FM : >>8(AK) fixed , >>4,5,6 (WM boost OFF) + if (new_audio_shift_bits_s16==8) { //FM : we are in AK codec IC => for AM-SSB-DSB we were using >>2 fixed (wm boost ON) . + audio_shift_bits_s16_AM_DSB_SSB = 2; //AM-DSB-SSB: >>2(AK) fixed , >>0,1,2 (WM boost OFF) + } else { + audio_shift_bits_s16_AM_DSB_SSB = (new_audio_shift_bits_s16-4) ; //AM-DSB-SSB: >>0,1,2 (WM boost OFF), >>2,3 (WM boost ON) + } 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 ) { @@ -85,7 +91,7 @@ void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& co if (counter % 128 == 0) { float i = 0.0, q = 0.0; - sample = audio.p[counter / over] >> 2; + sample = audio.p[counter / over] >> audio_shift_bits_s16_AM_DSB_SSB; // originally fixed >> 2, now >>2 for AK, 0,1,2,3 for WM (boost off) sample *= audio_gain; // Apply GAIN Scale factor to the audio TX modulation. //switch (mode) { @@ -145,7 +151,7 @@ void FM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& con for (size_t counter = 0; counter < buffer.count; counter++) { - sample = audio.p[counter>>6] >> 8; // sample = audio.p[counter / over] >> 8; (not enough efficient running code, over = 1536000/240000= 64 ) + sample = audio.p[counter>>6] >> audio_shift_bits_s16_FM ; // Orig. >>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) { @@ -190,7 +196,7 @@ void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer, bool& con for (size_t counter = 0; counter < buffer.count; counter++) { if (counter % 128 == 0) { - sample = audio.p[counter / over] >> 2; + sample = audio.p[counter / over] >> audio_shift_bits_s16_AM_DSB_SSB; // originally fixed >> 2, now >>2 for AK, 0,1,2,3 for WM (boost off) sample *= audio_gain; // Apply GAIN Scale factor to the audio TX modulation. } diff --git a/firmware/baseband/dsp_modulate.hpp b/firmware/baseband/dsp_modulate.hpp index de964a68..e8a2c432 100644 --- a/firmware/baseband/dsp_modulate.hpp +++ b/firmware/baseband/dsp_modulate.hpp @@ -50,9 +50,11 @@ public: 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 ); + void set_gain_shiftbits_vumeter_beep(float new_audio_gain ,uint8_t new_audio_shift_bits_s16, 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 { }; + uint8_t audio_shift_bits_s16_FM { }; // shift bits factor to the captured ADC S16 audio sample. + uint8_t audio_shift_bits_s16_AM_DSB_SSB { }; 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 diff --git a/firmware/baseband/proc_mictx.cpp b/firmware/baseband/proc_mictx.cpp index 6c9c9b97..1ee5b94d 100644 --- a/firmware/baseband/proc_mictx.cpp +++ b/firmware/baseband/proc_mictx.cpp @@ -35,7 +35,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){ if (!configured) return; audio_input.read_audio_buffer(audio_buffer); - modulator->set_gain_vumeter_beep(audio_gain, play_beep ) ; + modulator->set_gain_shiftbits_vumeter_beep(audio_gain, audio_shift_bits_s16, 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 @@ -141,6 +141,7 @@ void MicTXProcessor::on_message(const Message* const msg) { } audio_gain = config_message.audio_gain; + audio_shift_bits_s16 = config_message.audio_shift_bits_s16; divider = config_message.divider; power_acc_count = 0; diff --git a/firmware/baseband/proc_mictx.hpp b/firmware/baseband/proc_mictx.hpp index 175e53c7..59a07cb0 100644 --- a/firmware/baseband/proc_mictx.hpp +++ b/firmware/baseband/proc_mictx.hpp @@ -61,6 +61,8 @@ private: uint32_t divider { }; float audio_gain { }; + uint8_t audio_shift_bits_s16 { } ; // shift bits factor to the captured ADC S16 audio sample. + uint64_t power_acc { 0 }; uint32_t power_acc_count { 0 }; bool play_beep { false }; diff --git a/firmware/common/ak4951.cpp b/firmware/common/ak4951.cpp index 74301ecb..1f88a3d6 100644 --- a/firmware/common/ak4951.cpp +++ b/firmware/common/ak4951.cpp @@ -216,90 +216,347 @@ void AK4951::speaker_disable() { set_speaker_power(false); } -void AK4951::microphone_enable() { -// map.r.digital_mic.DMIC = 0; -// update(Register::DigitalMic); +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 - 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); + // 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; - 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); + 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.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); + // 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; - map.r.alc_timer_select. = ?; - update(Register::ALCTimerSelect); - map.r.alc_mode_control_1. = ?; - map.r.alc_mode_control_1.ALC = 1; + 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.alc_mode_control_2.REF = ?; + 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. + 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.) + 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) + 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) update(Register::ALCModeControl2); -*/ -// 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; + + // 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) update(Register::DigitalFilterSelect2); - 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); + // 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 ) // 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; - map.r.power_management_1.PMADR = 0; - map.r.power_management_1.PMPFIL = 0; + 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 update(Register::PowerManagement1); - map.r.alc_mode_control_1.ALC = 0; + map.r.alc_mode_control_1.ALC = 0; // original code , Restore , disable ALC block. 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 df168a09..3b1f9e1a 100644 --- a/firmware/common/ak4951.hpp +++ b/firmware/common/ak4951.hpp @@ -773,40 +773,41 @@ constexpr RegisterMap default_after_reset { Register_Type { .REV = 0b1100, }, - .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 }, + // 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 - .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 }, + .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 - .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 }, + .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 - .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 }, + .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 - .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 }, + .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 } }; class AK4951 : public audio::Codec { @@ -841,7 +842,7 @@ public: void set_headphone_volume(const volume_t volume) override; void headphone_mute(); - void microphone_enable(); + void microphone_enable(int8_t alc_mode); // added user GUI parameter , to set up AK4951 ALC mode. void microphone_disable(); size_t reg_count() const override { diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index 172aff88..38bc1217 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -868,6 +868,7 @@ public: const uint32_t divider, const float deviation_hz, const float audio_gain, + const uint8_t audio_shift_bits_s16, const uint32_t tone_key_delta, const float tone_key_mix_weight, const bool am_enabled, @@ -878,6 +879,7 @@ public: divider(divider), deviation_hz(deviation_hz), audio_gain(audio_gain), + audio_shift_bits_s16(audio_shift_bits_s16), tone_key_delta(tone_key_delta), tone_key_mix_weight(tone_key_mix_weight), am_enabled(am_enabled), @@ -890,6 +892,7 @@ public: const uint32_t divider; const float deviation_hz; const float audio_gain; + const uint8_t audio_shift_bits_s16; const uint32_t tone_key_delta; const float tone_key_mix_weight; const bool am_enabled; diff --git a/firmware/common/wm8731.cpp b/firmware/common/wm8731.cpp index 25686c1c..82aefdc8 100644 --- a/firmware/common/wm8731.cpp +++ b/firmware/common/wm8731.cpp @@ -84,7 +84,7 @@ void WM8731::init() { }); write(AnalogAudioPathControl { - .micboost = 1, // Enable 20dB boost + .micboost = 0, // Disable 20dB boost by default .mutemic = 0, // Disable mute (unmute) .insel = 1, // Microphone input to ADC .bypass = 0, diff --git a/firmware/common/wm8731.hpp b/firmware/common/wm8731.hpp index a5c8908b..bd3d5cb0 100644 --- a/firmware/common/wm8731.hpp +++ b/firmware/common/wm8731.hpp @@ -345,18 +345,28 @@ public: void speaker_disable() {}; - void microphone_enable() override { - // TODO: Implement - } +void microphone_enable(int8_t wm8731_boost_GUI) override { + microphone_mute(true); // c/m to reduce "plop noise" when changing wm8731_boost_GUI. + // chThdSleepMilliseconds(20); // does not help to reduce the "plop noise" + microphone_boost((wm8731_boost_GUI<2) ? 1 : 0 ); // 1 = Enable Boost (+20 dBs) . 0 = Disable Boost (0dBs). + chThdSleepMilliseconds(120); // >50 msegs, very effective , >100 msegs minor improvement ,120 msegs trade off speed . + microphone_mute(false); + // (void)alc_mode; In prev. fw version , when we did not use at all param., to avoid "unused warning" when compiling.) +} void microphone_disable() override { // TODO: Implement } - // void microphone_mute(const bool mute) { - // map.r.analog_audio_path_control.mutemic = (mute ? 0 : 1); - // write(Register::AnalogAudioPathControl); - // } + void microphone_boost(const bool boost) { + map.r.analog_audio_path_control.micboost = (boost ? 1 : 0); + write(Register::AnalogAudioPathControl); + } + + void microphone_mute(const bool mute) { + map.r.analog_audio_path_control.mutemic = (mute ? 1 : 0); //1 = Enable Mute , 0 = Disable Mute + write(Register::AnalogAudioPathControl); + } // void set_adc_source(const ADCSource adc_source) { // map.r.analog_audio_path_control.insel = toUType(adc_source);