diff --git a/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/audiohw.xc b/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/audiohw.xc index 2e548b5..e86da8a 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/audiohw.xc +++ b/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/audiohw.xc @@ -116,6 +116,14 @@ timer tm; // 改动原因:与 FORMAT_DELAY(30000000) 相同时间基准(get_reference_time 滴答),用户停止调节 300ms 后再写 Flash,减少磨损并满足需求。 #define C1_DAC_VOL_SAVE_DELAY (30000000) +// 改动原因:XS1_PORT_4E 耳机/MIC 插入检测位定义——bit2 高=耳机插入;bit3 低=MIC 插入、高=拔出(与硬件原理图一致)。 +#define C1_HP_DETECT_MASK 0x04u +#define C1_MIC_DETECT_MASK 0x08u +// 改动原因:插入后延迟与 EQ_SYNC_DELAY 相同 tick(get_reference_time),固定 500ms 再恢复 DAC/ADC 硬件音量,减轻插拔 pop。 +#define C1_JACK_RESTORE_DELAY EQ_SYNC_DELAY +// 改动原因:TIMER_PERIOD≈20ms,连续 3 次采样一致再认定电平稳定,避免检测脚抖动误触发。 +#define C1_JACK_DEBOUNCE_SAMPLES 3u + // 改动原因:判断 Flash 读出字节是否为合法 NAU88C22 DAC 音量码:0x00 表示按键规则下的 mute,0x4B~0xCF 为正常衰减范围。 static unsigned c1_saved_dac_vol_is_valid(unsigned char v) { @@ -137,9 +145,9 @@ static inline unsigned c1_mode_to_led_color_idx(unsigned mode_value) #define NAU88L21_PGA_GAIN_REG_MAX_VALUE 0x25+1 // 0x25=37, 36dB. +1 is for extra 1.5dB digital gain #define NAU88L21_PGA_GAIN_REG_DEFAULT_VALUE (NAU88L21_PGA_GAIN_REG_MAX_VALUE) -// CODEC reset line -on tile[0]: out port p_mclk_sel = XS1_PORT_4E; -on tile[0]: out port p_gpio = XS1_PORT_4F; +// 改动原因:4E 为耳机/MIC 检测输入(读 bit2/bit3),原先声明为 out 无法采样;改为 in port 与硬件方向一致。 +on tile[0]: in port p_mic_phone_detect = XS1_PORT_4E; +on tile[0]: out port p_gpio = XS1_PORT_4F; #define LED_OFF 0x7F // 修改:清除最高位,只保留低7位 #define LED_RED 0b01011111 // 修改:清除最高位,只保留低7位 @@ -391,6 +399,28 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli // 改动原因:记录上次用于防抖持久化的 g_dac_vol;deadline=0 表示当前无待写入 Flash 的定时保存任务。 unsigned dac_vol_persist_snapshot = 0; unsigned dac_vol_persist_deadline = 0; + // 改动原因:耳机拔出强制 DAC 寄存器静音(不改 g_dac_vol,类比 phaten 的 dac_det_muted);插入后延时再写回逻辑音量。 + unsigned hp_jack_dac_mute = 0; + unsigned hp_restore_deadline = 0; + unsigned hp_stable_prev = 0xFFFFFFFFu; + unsigned hp_db_cnt = 0; + unsigned hp_cand = 0xFFFFFFFFu; + unsigned hp_stable = 0; + // 改动原因:记录上次写入 0x0034 时的“插拔强制哑音”组合态(耳机拔出 | MIC 拔出 | MIC 插入),任一路变化都要重推寄存器。 + unsigned old_dac_jack_force_mute = 0; + // 改动原因:MIC 拔出瞬间哑 DAC(参考 phaten MIC_DET_DAC_MUTE),拔出边沿起 500ms 后恢复 DAC 寄存器;不改 g_dac_vol。 + unsigned mic_pull_dac_mute = 0; + unsigned mic_pull_dac_deadline = 0; + // 改动原因:MIC 插入(去抖稳定后)立即哑 DAC 防 pop,稳定插入起再计 500ms 后恢复 DAC;拔出时清零;不改 g_dac_vol。 + unsigned mic_insert_dac_mute = 0; + unsigned mic_insert_dac_deadline = 0; + // 改动原因:MIC 拔出强制 ADC mute;插入 500ms 后按 g_mute_switch+g_adc_vol 恢复,不修改 g_mute_switch,故 mic mute LED 不受插拔影响。 + unsigned mic_jack_adc_mute = 0; + unsigned mic_restore_deadline = 0; + unsigned mic_stable_prev = 0xFFFFFFFFu; + unsigned mic_db_cnt = 0; + unsigned mic_cand = 0xFFFFFFFFu; + unsigned mic_stable = 0; // 改动原因:按DS1按键状态机思路保存每个按键按下时长;mode/mic 仍用短/长按窗口区分,音量键仅用于释放时短按去抖(不支持长按连调)。 unsigned mode_press_ticks = 0; unsigned vol_down_press_ticks = 0; @@ -522,6 +552,88 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli } } } + // 改动原因:耳机/MIC 插拔检测——写 NAU88C22(0x0034 / mic_volume);不修改 g_dac_vol、g_mute_switch;MIC 插/拔均对 DAC 做瞬时静音+500ms 恢复防 pop。 + { + unsigned raw_det; + p_mic_phone_detect :> raw_det; + unsigned hp_now = ((raw_det & C1_HP_DETECT_MASK) != 0) ? 1u : 0u; + unsigned mic_now = ((raw_det & C1_MIC_DETECT_MASK) == 0) ? 1u : 0u; + if (hp_cand == 0xFFFFFFFFu) { + hp_cand = hp_now; + hp_stable = hp_now; + hp_db_cnt = 0; + } else if (hp_now == hp_cand) { + hp_db_cnt++; + if (hp_db_cnt >= C1_JACK_DEBOUNCE_SAMPLES) { + hp_stable = hp_cand; + } + } else { + hp_cand = hp_now; + hp_db_cnt = 1; + } + if (mic_cand == 0xFFFFFFFFu) { + mic_cand = mic_now; + mic_stable = mic_now; + mic_db_cnt = 0; + } else if (mic_now == mic_cand) { + mic_db_cnt++; + if (mic_db_cnt >= C1_JACK_DEBOUNCE_SAMPLES) { + mic_stable = mic_cand; + } + } else { + mic_cand = mic_now; + mic_db_cnt = 1; + } + if (hp_stable_prev == 0xFFFFFFFFu) { + hp_stable_prev = hp_stable; + mic_stable_prev = mic_stable; + } else { + if (!hp_stable) { + hp_jack_dac_mute = 1; + hp_restore_deadline = 0; + } else { + if (hp_stable && !hp_stable_prev) { + hp_restore_deadline = now + C1_JACK_RESTORE_DELAY; + } + if (hp_jack_dac_mute && hp_restore_deadline != 0 && timeafter(now, hp_restore_deadline)) { + hp_jack_dac_mute = 0; + } + } + if (!mic_stable) { + mic_jack_adc_mute = 1; + mic_restore_deadline = 0; + mic_insert_dac_mute = 0; + mic_insert_dac_deadline = 0; + // 改动原因:MIC 拔出边沿立即拉 DAC 寄存器静音,减轻瞬态 pop;满 500ms(相对拔出时刻)后 mic_pull_dac_mute 清零恢复 g_dac_vol 对应音量。 + if (mic_stable_prev) { + mic_pull_dac_mute = 1; + mic_pull_dac_deadline = now + C1_JACK_RESTORE_DELAY; + } + if (mic_pull_dac_deadline != 0 && timeafter(now, mic_pull_dac_deadline)) { + mic_pull_dac_mute = 0; + mic_pull_dac_deadline = 0; + } + } else { + mic_pull_dac_mute = 0; + mic_pull_dac_deadline = 0; + // 改动原因:去抖后由拔出→插入的边沿:立刻 mic_insert_dac_mute 哑 DAC;自该稳定插入时刻起 500ms 后清除以恢复 g_dac_vol(与 ADC 的 mic_restore 同源边沿,时间基准一致)。 + if (mic_stable && !mic_stable_prev) { + mic_restore_deadline = now + C1_JACK_RESTORE_DELAY; + mic_insert_dac_mute = 1; + mic_insert_dac_deadline = now + C1_JACK_RESTORE_DELAY; + } + if (mic_jack_adc_mute && mic_restore_deadline != 0 && timeafter(now, mic_restore_deadline)) { + mic_jack_adc_mute = 0; + } + if (mic_insert_dac_mute && mic_insert_dac_deadline != 0 && timeafter(now, mic_insert_dac_deadline)) { + mic_insert_dac_mute = 0; + mic_insert_dac_deadline = 0; + } + } + hp_stable_prev = hp_stable; + mic_stable_prev = mic_stable; + } + } GET_SHARED_GLOBAL(dac_vol, g_dac_vol); GET_SHARED_GLOBAL(adc_vol, g_adc_vol); unsigned mute_switch; @@ -532,16 +644,20 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli i_c1_led_ctrl.set_mic_mute_state(mute_switch); last_mute_switch_for_led = mute_switch; } - // 改动原因:静音时(g_mute_switch==1) ADC 音量写 0,未静音时写 g_adc_vol;g_mute_switch 变化时也需更新 - unsigned effective_adc_vol = (mute_switch != 0) ? 0 : adc_vol; + // 改动原因:MIC 物理拔出时 mic_jack_adc_mute 强制 ADC 静音;插入 500ms 内仍保持静音,之后恢复 g_mute_switch 与 g_adc_vol 决定的电平(不触碰 LED 条件 mute_switch)。 + unsigned effective_adc_vol = mic_jack_adc_mute ? 0 : ((mute_switch != 0) ? 0 : adc_vol); - if (old_dac_vol != dac_vol || old_type != audio_type) + // 改动原因:耳机拔出或 MIC 插/拔防 pop 时写 C1_DAC_MUTE(不改 g_dac_vol);各事件满 500ms 或互斥清除后按 g_dac_vol 写回 0x0034。 { - old_dac_vol = dac_vol; - // 改动原因:实体按键、HID和UART都会更新g_dac_vol;这里统一把寄存器值写入codec,保证状态变化真正生效。 - NAU88C22_REGWRITE(0x0034, ((dac_vol & 0xff) << 8) | (dac_vol & 0xff), i2c); - SET_SHARED_GLOBAL(g_old_audio_type, audio_type); - debug_printf("set old_dac_vol %d audio_type %d \n", old_dac_vol, audio_type); + unsigned dac_jack_force_mute = hp_jack_dac_mute | mic_pull_dac_mute | mic_insert_dac_mute; + unsigned dac_reg = dac_jack_force_mute ? C1_DAC_MUTE : (dac_vol & 0xff); + if (old_dac_vol != dac_vol || old_type != audio_type || old_dac_jack_force_mute != dac_jack_force_mute) { + old_dac_vol = dac_vol; + old_dac_jack_force_mute = dac_jack_force_mute; + NAU88C22_REGWRITE(0x0034, ((dac_reg & 0xff) << 8) | (dac_reg & 0xff), i2c); + SET_SHARED_GLOBAL(g_old_audio_type, audio_type); + debug_printf("set dac_reg 0x%x (hp=%d mic_pull=%d mic_ins=%d) audio_type %d \n", dac_reg, hp_jack_dac_mute, mic_pull_dac_mute, mic_insert_dac_mute, audio_type); + } } // 改动原因:音量键/HID/UART 任一修改 g_dac_vol 后不立即写 Flash;仅当读回值相对 persist_snapshot 稳定满 300ms 再 save_value,满足防抖与关机保存。 @@ -1244,7 +1360,6 @@ void AudioHwInit() { debug_printf("AudioHwInit\n"); delay_milliseconds(100); - p_mclk_sel <: 0xf; if((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && XUA_USE_SW_PLL) { @@ -1255,12 +1370,10 @@ void AudioHwInit() if (DEFAULT_FREQ % 22050 == 0) { sw_pll_fixed_clock(MCLK_441); - //p_mclk_sel <: 0x8; } else { sw_pll_fixed_clock(MCLK_48); - //p_mclk_sel <: 0x4; } } @@ -1516,12 +1629,10 @@ void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, if (samFreq % 22050 == 0) { sw_pll_fixed_clock(MCLK_441); - //p_mclk_sel <: 0x8; } else { sw_pll_fixed_clock(MCLK_48); - //p_mclk_sel <: 0x4; } }