From 7781eaebe6e263484ca2c3b5fcbaf6fae16ae9ee Mon Sep 17 00:00:00 2001 From: Steven Dan Date: Mon, 1 Jun 2026 16:00:15 +0800 Subject: [PATCH] fix high_perf toggle noise and USB stall from blocking LFS Root cause: each GAME+MIC toggle ran two synchronous Flash writes (hi_perf + dac_vol) in the 20ms timer, blocking AudioHwRemote2. Now apply DAC with brief mute only, defer hi_perf Flash, and skip redundant dac_vol save when user level unchanged. Co-authored-by: Cursor --- .../src/extensions/audiohw.xc | 72 +++++++++++++++---- 1 file changed, 58 insertions(+), 14 deletions(-) diff --git a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/audiohw.xc b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/audiohw.xc index 5510395..9dd0a30 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/audiohw.xc +++ b/sw_usb_audio/app_usb_aud_fosi_c1_v71/src/extensions/audiohw.xc @@ -60,6 +60,8 @@ unsigned g_dnr_enable = 1; unsigned g_3d_enable = 1; /* 改动原因:GAME+MIC 高性能模式,0=DAC 在用户等级基础上减 6 格(约 -6dB),1=不减;默认 0 */ unsigned g_high_perf_mode = 0; +/* 改动原因:high_perf 不在组合键回调里写 Flash,避免 lfs_init/deinit 阻塞导致 USB 卡死 */ +unsigned g_high_perf_save_pending = 0; unsigned g_led_mode = 0; unsigned g_fps_enable = 0; uint32_t get_reference_time(); @@ -598,6 +600,34 @@ static void tx1_apply_dac_hid_level(unsigned hid_level) SET_SHARED_GLOBAL(g_request_volume_set, 1); } +/** + * 改动原因:high_perf 切换时直接写 0x0034,不经 g_request_volume_set,避免同 tick 再写 Flash。 + */ +static void tx1_write_dac_hw_reg(unsigned eff_hid, unsigned reg, + unsigned &old_dac_vol, + client interface i2c_master_if i2c) +{ + SET_SHARED_GLOBAL(g_dac_vol, reg); + if (eff_hid == 0) { + unsafe { NAU88C22_REGWRITE(0x0034, 0x0000, i2c); } + } else { + unsafe { + NAU88C22_REGWRITE(0x0034, ((reg & 0xff) << 8) | (reg & 0xff), i2c); + } + } + old_dac_vol = reg; +} + +static void tx1_apply_dac_hw_from_user_level(unsigned user_hid, unsigned high_perf, + unsigned &old_dac_vol, + client interface i2c_master_if i2c) +{ + unsigned eff_hid = tx1_effective_dac_hid_level(user_hid, high_perf); + unsigned reg = tx1_dac_reg_from_hid_level(eff_hid); + + tx1_write_dac_hw_reg(eff_hid, reg, old_dac_vol, i2c); +} + /* 改动原因:统一把 MIC HID 等级写入 g_mic_volume_level/g_adc_vol,定时器请求分支 mic_volume 写 ADC 并 Flash */ static void tx1_apply_mic_hid_level(unsigned hid_level) { @@ -1425,6 +1455,8 @@ void AudioHwRemote2(streaming chanend c, chanend cc_mic_level, client interface unsigned factory_reset_6s_fired = 0; unsigned factory_reset_10s_fired = 0; unsigned factory_reset_done = 0; + /* 改动原因:仅用户真实改音量时写 tx1_dac_vol Flash;high_perf 切换不重写 */ + unsigned last_saved_dac_hid = 255; // TX1 LED effect state for game mode indicators unsigned gpio_leds_dirty = 1; // refresh LEDs on first tick @@ -1491,6 +1523,7 @@ void AudioHwRemote2(streaming chanend c, chanend cc_mic_level, client interface } high_perf_mode = (unsigned)saved_hp; SET_SHARED_GLOBAL(g_high_perf_mode, high_perf_mode); + last_saved_dac_hid = (unsigned)saved_dac; tx1_apply_dac_hid_level((unsigned)saved_dac); tx1_apply_mic_hid_level((unsigned)saved_mic); feature_volume = tx1_hid_level_to_bar((unsigned)saved_mic); @@ -1623,23 +1656,27 @@ void AudioHwRemote2(streaming chanend c, chanend cc_mic_level, client interface if (user_hid <= TX1_DAC_HID_LEVEL_MAX) { eff_hid = tx1_effective_dac_hid_level(user_hid, hp); reg = tx1_dac_reg_from_hid_level(eff_hid); - SET_SHARED_GLOBAL(g_dac_vol, reg); - if (eff_hid == 0) { - unsafe { NAU88C22_REGWRITE(0x0034, 0x0000, i2c); } - } else { - /* 改动原因:必须用 SY102 查表值直写 0x0034,不能用 dac_volume 线性公式 */ - unsafe { - NAU88C22_REGWRITE(0x0034, - ((reg & 0xff) << 8) | (reg & 0xff), i2c); - } + tx1_write_dac_hw_reg(eff_hid, reg, old_dac_vol, i2c); + if (user_hid != last_saved_dac_hid) { + tx1_save_dac_volume((unsigned char)user_hid); + last_saved_dac_hid = user_hid; } - old_dac_vol = reg; - tx1_save_dac_volume((unsigned char)user_hid); debug_printf("HID/panel SET_VOLUME: user_hid=%u eff_hid=%u hp=%u reg=0x%x\n", user_hid, eff_hid, hp, reg); } } } + { + unsigned hp_save; + GET_SHARED_GLOBAL(hp_save, g_high_perf_save_pending); + if (hp_save) { + unsigned hp_val; + GET_SHARED_GLOBAL(hp_val, g_high_perf_mode); + tx1_save_high_perf_mode((unsigned char)hp_val); + SET_SHARED_GLOBAL(g_high_perf_save_pending, 0); + debug_printf("TX1: deferred save high_perf=%u\n", hp_val); + } + } { unsigned req_mic; GET_SHARED_GLOBAL(req_mic, g_request_mic_volume_set); @@ -2187,12 +2224,19 @@ void AudioHwRemote2(streaming chanend c, chanend cc_mic_level, client interface if (current_combo != COMBO_NONE && !combo_triggered) { combo_triggered = 1; if (current_combo == COMBO_GAME_MIC) { + unsigned user_dac_hid; + GET_SHARED_GLOBAL(user_dac_hid, g_volume_level); high_perf_mode = !high_perf_mode; SET_SHARED_GLOBAL(g_high_perf_mode, high_perf_mode); - tx1_save_high_perf_mode((unsigned char)high_perf_mode); - SET_SHARED_GLOBAL(g_request_volume_set, 1); + SET_SHARED_GLOBAL(g_high_perf_save_pending, 1); + /* 改动原因:先静音再改 0x0034,减轻 ±6dB 切换 pop;不写 Flash/不置 request_volume */ + tx1_amp_ctl_mute_force(led_if, TX1_AMP_CTL_MUTE_VAL); + tx1_apply_dac_hw_from_user_level(user_dac_hid, high_perf_mode, + old_dac_vol, i2c); + tx1_amp_ctl_mute_force(led_if, TX1_AMP_CTL_UNMUTE_VAL); gpio_leds_dirty = 1; - debug_printf("TX1: GAME+MIC combo - high_perf_mode=%d\n", high_perf_mode); + debug_printf("TX1: GAME+MIC combo - high_perf_mode=%d user_hid=%u\n", + high_perf_mode, user_dac_hid); } else if (current_combo == COMBO_VOL_UP_DOWN) { /* 改动原因:无 BYPASS 档;feature 空闲时 VOL 组合键可切换 RGB 装饰灯效 */ if (feature_mode == FEATURE_MODE_NONE) {