From e6de9593661911107c4b5844cef453d99e888997 Mon Sep 17 00:00:00 2001 From: yuquanjun Date: Sat, 26 Sep 2026 07:35:09 +0800 Subject: [PATCH] fix(pwr): keep the pack above 6.8V and unmute the amp after 12V is up Show the real battery percent, shut down at 6.8V even while Type-C is connected, and leave the charge screen dark so it does not drain the pack. Initialize the amplifier only after the 12V rail has settled. Co-authored-by: Cursor --- APP/app_adc.c | 23 ++++---- APP/app_log.h | 2 +- Global/Global.c | 114 ++++++++++++++++++++++++++++++++---- Global/Global.h | 8 +++ UI/UI_Idle.c | 24 +++----- project/src/main.c | 8 ++- task/task_init.c | 5 +- tools/publish_k1_release.py | 2 +- 8 files changed, 143 insertions(+), 43 deletions(-) diff --git a/APP/app_adc.c b/APP/app_adc.c index d65b789..705e560 100644 --- a/APP/app_adc.c +++ b/APP/app_adc.c @@ -65,16 +65,16 @@ uint8_t percentage = 0; //static uint32_t charge_step_tick = 0; #define VBAT_MIN_RAW 2520 #define VBAT_MAX_RAW 3528 -/* 包电压标定:MIN≈6.0V(0%) … MAX≈8.4V(100%);关机阈值 6.2V */ +/* 包电压标定:MIN≈6.0V(0%) … MAX≈8.4V(100%);关机阈值 6.8V(每节 3.4V) */ #define VBAT_PACK_V_MIN_MV 6000 #define VBAT_PACK_V_MAX_MV 8400 -#define VBAT_SHUTDOWN_MV 6200 +#define VBAT_SHUTDOWN_MV 6800 #define VBAT_SHUTDOWN_RAW \ (VBAT_MIN_RAW + (uint32_t)(VBAT_SHUTDOWN_MV - VBAT_PACK_V_MIN_MV) * \ (VBAT_MAX_RAW - VBAT_MIN_RAW) / (VBAT_PACK_V_MAX_MV - VBAT_PACK_V_MIN_MV)) -/* 接近关机阈值时加快采样(约 <6.5V) */ +/* 7.2V 以下加快采样,避免从 6.8V 掉到保护电压时还要等 30s */ #define VBAT_FAST_SAMPLE_RAW \ - (VBAT_MIN_RAW + (uint32_t)(500) * (VBAT_MAX_RAW - VBAT_MIN_RAW) / \ + (VBAT_MIN_RAW + (uint32_t)(1200) * (VBAT_MAX_RAW - VBAT_MIN_RAW) / \ (VBAT_PACK_V_MAX_MV - VBAT_PACK_V_MIN_MV)) #define BAT_SAMPLE_INTERVAL_LOW_MS 2000 @@ -396,7 +396,7 @@ static void app_adc_battery_do_sample(void) bat_index = (bat_index + 1) % BAT_SAMPLE_COUNT; } -/* 上报:映射成百分比,变化才发消息;低于 6.2V 触发低电量关机流程 */ +/* 上报:映射成百分比,变化才发消息;低于 6.8V 触发低电量关机(插着 Type-C 也执行) */ static void app_adc_battery_report(void) { uint16_t filtered = bat_sum / BAT_SAMPLE_COUNT; @@ -407,11 +407,10 @@ static void app_adc_battery_report(void) else if (filtered > VBAT_MAX_RAW) pct = 100; else - pct = 100 * (filtered - VBAT_MIN_RAW) / (VBAT_MAX_RAW - VBAT_MIN_RAW); - pct = (pct / 10) * 10; + pct = (uint8_t)(100 * (filtered - VBAT_MIN_RAW) / (VBAT_MAX_RAW - VBAT_MIN_RAW)); - /* 开机且未充电:包电压低于 6.2V → 立即停声并弹关机提示(只触发一次) */ - if (powon && !usb_charging_state && !System_LowBat_IsActive() && + /* 开机使用中包电压低于 6.8V:停负载并关机。插着 Type-C 同样执行,避免边充边用拉过保护电压 */ + if (powon && !System_LowBat_IsActive() && filtered < (uint16_t)VBAT_SHUTDOWN_RAW) { LOG_W("BAT", "lowbat raw=%u thr=%u → tip+shutdown", @@ -451,7 +450,8 @@ static void app_adc_battery_process(void) { uint32_t interval = BAT_SAMPLE_INTERVAL_MS; uint16_t last_avg = bat_sum / BAT_SAMPLE_COUNT; - if (last_avg != 0 && last_avg < (uint16_t)VBAT_FAST_SAMPLE_RAW) + /* 关机充电不加快采样,避免每 2 秒停一次充电 */ + if (powon && last_avg != 0 && last_avg < (uint16_t)VBAT_FAST_SAMPLE_RAW) interval = BAT_SAMPLE_INTERVAL_LOW_MS; if (now - bat_last_sample_tick >= interval) bat_state = BAT_START; @@ -459,7 +459,8 @@ static void app_adc_battery_process(void) break; case BAT_START: - if (usb_charging_state) /* 充电中:先停充电,采真实电压 */ + /* 关机充电不中断充电芯片。开机中才短暂停充,读负载下的真实电压 */ + if (powon && usb_charging_state) { BSP_ChargerEnable(0); bat_charge_paused = 1; diff --git a/APP/app_log.h b/APP/app_log.h index 29062e5..32e26a8 100644 --- a/APP/app_log.h +++ b/APP/app_log.h @@ -12,7 +12,7 @@ #endif #ifndef APP_LOG_RAM_SIZE -#define APP_LOG_RAM_SIZE (4U * 1024U) +#define APP_LOG_RAM_SIZE ((4U * 1024U) - 128U) #endif #ifndef APP_LOG_SLOT_SIZE diff --git a/Global/Global.c b/Global/Global.c index 569e31d..46b5bbe 100644 --- a/Global/Global.c +++ b/Global/Global.c @@ -111,7 +111,7 @@ int16_t MIC_VOL_MAP[11]= {-9000,-7000,-5000,-3000,-1000,1000,3000,5000,7000,9000 uint8_t TOUCH_AREA_NUM = (sizeof(Touch_Areas)/sizeof(Touch_AreaTypeDef)); -const uint8_t Version[3] = {0,2,31}; /* major.minor.patch — 0.2.31: 充电开机先出模式选择,避免卡在 Logo */ +const uint8_t Version[3] = {0,2,35}; /* major.minor.patch — 0.2.35: 12V稳定后再初始化功放,避免开机无声 */ uint8_t Led = 8; bool PressFlag = 0; @@ -204,7 +204,7 @@ static volatile uint8_t s_pwr_rails_cut = 0; /* TMR7:关机长按已触发请求后的紧急倒计时(ms) */ static volatile uint16_t s_pwr_off_grace_ms = 0; -/* 电量 <6.2V:提示界面停留后关机 */ +/* 电量 <6.8V:提示界面停留后关机(插着 Type-C 也停负载) */ #define LOWBAT_SHUTDOWN_DELAY_MS 10000u static volatile uint8_t s_lowbat_active = 0; static volatile uint32_t s_lowbat_deadline_ms = 0; @@ -244,27 +244,111 @@ void System_PowerOn(void) s_lowbat_deadline_ms = 0u; /* 本次长按已用于开机:先消耗,再置 powon,防止 TMR7 ISR 把同一按压力即判为关机 */ Power_Key_ConsumePress(); - /* 控制电源硬件;蓝牙按 NVM/系统设置开关恢复,勿强制常开 */ + /* 彩灯期间只留主电和侧灯。12V 升压、Dream、功放、蓝牙在 Logo 彩灯结束后再开 */ BSP_MainPowerEnable(1); - BSP_DreamCorePowerEnable(1); - BSP_HT7178PowerEnable(1); - /* 蓝牙按 NVM/系统设置开关恢复,勿强制常开 */ - BSP_BlueToothPowerEnable((uint8_t)(mGuiData[GUI_BL_SW].Current ? 1 : 0)); + BSP_DreamCorePowerEnable(0); + BSP_HT7178PowerEnable(0); + BSP_BlueToothPowerEnable(0); powon = true; /* 更新开机标志 */ - /* 侧灯驱动先就绪,模式页出来前保持全灭(勿在 Logo 前打满 8 颗键灯) */ + /* 侧灯驱动先就绪,彩灯由 UI 在 Logo 画面上播放 */ TM1629D_Key_LED_Init(); app_tm1617_init(); - /* 先通知 UI 亮屏,避免外设初始化阻塞导致长时间黑屏 */ - LOG_I("PWR", "send POWER_ON"); + LOG_I("PWR", "send POWER_ON (logo+led, audio rails off)"); MainTask_Sendmsg(MSG_ID_POWER_ON, 0, 0, 0); +} +void Power_LogRails(const char *where) +{ + unsigned main_on = (unsigned)(gpio_output_data_bit_read(S_PWR_ON_OFF_GPIO_Port, S_PWR_ON_OFF_Pin) == SET); + unsigned dream_on = (unsigned)(gpio_output_data_bit_read(P_CORE_PWR_GPIO_Port, P_CORE_PWR_Pin) == SET); + unsigned v12_on = (unsigned)(gpio_output_data_bit_read(S_HT7178_EN_GPIO_Port, S_HT7178_EN_Pin) == SET); + unsigned bt_on = (unsigned)(gpio_output_data_bit_read(S_BT_PWR_GPIO_Port, S_BT_PWR_Pin) == SET); + /* 充电使能低有效:引脚为低记 chg=1 */ + unsigned chg_on = (unsigned)(gpio_output_data_bit_read(S_CHARGE_CTRL_GPIO_Port, S_CHARGE_CTRL_Pin) == RESET); + unsigned bl_on = (unsigned)(gpio_output_data_bit_read(LCD_BLK_PORT, LCD_BLK_PIN) == SET); + + LOG_I("PWR", "%s powon=%u main=%u dream=%u v12=%u bt=%u chg=%u bl=%u usb=%u pct=%u", + where ? where : "?", + (unsigned)powon, main_on, dream_on, v12_on, bt_on, chg_on, bl_on, + (unsigned)usb_charging_state, (unsigned)percentage); +} + +/* 关机充电:只留主电给屏幕,其余外设必须关掉 */ +static void Power_QuiesceForCharge(const char *where) +{ + BSP_DreamCorePowerEnable(0); + BSP_HT7178PowerEnable(0); + BSP_BlueToothPowerEnable(0); + Power_LogRails(where); +} + +/* UI 播完开机彩灯后请求;由主循环执行,避免功放 I2C 堵死触摸 */ +static volatile uint8_t s_audio_bringup_req = 0; + +void System_RequestAudioBringUp(void) +{ + s_audio_bringup_req = 1; +} + +#define CHARGE_BL_HOLD_MS 3000u +static uint32_t s_charge_bl_off_at = 0; + +void Power_ChargeBacklightHold(void) +{ + LCD_BLK_Set(); + s_charge_bl_off_at = rt_tick_get() + (CHARGE_BL_HOLD_MS * RT_TICK_PER_SECOND / 1000u); +} + +void Power_ChargeIdle_LogPoll(void) +{ + static uint32_t s_last; + uint32_t now; + + if (powon) + { + s_charge_bl_off_at = 0; + return; + } + now = rt_tick_get(); + if (s_charge_bl_off_at != 0u && (int32_t)(now - s_charge_bl_off_at) >= 0) + { + LCD_BLK_Clr(); + s_charge_bl_off_at = 0; + LOG_I("PWR", "charge backlight off"); + } + if (s_last != 0u && (now - s_last) < (5u * RT_TICK_PER_SECOND)) + return; + s_last = now; + Power_LogRails("charge-idle"); +} + +extern uint8_t level; + +void System_AudioBringUp_Poll(void) +{ + if (!s_audio_bringup_req || !powon) + return; + s_audio_bringup_req = 0; + LOG_I("PWR", "bring up audio rails"); + BSP_DreamCorePowerEnable(1); + BSP_HT7178PowerEnable(1); + BSP_BlueToothPowerEnable((uint8_t)(mGuiData[GUI_BL_SW].Current ? 1 : 0)); + Power_LogRails("audio-up"); + /* 12V 升压刚打开时功放模拟电源未稳,立刻写寄存器会仍处于静音 */ + rt_thread_mdelay(80); AD85020B_Init(); - XPT2046_Init(); App_Auto_Init(); /* App 协议走 UART4:须在开机后即解析,不能等到触摸选模式才 StartTask */ StartTask(); + rt_thread_mdelay(400); + if (!powon) + return; + AD85020B_Init(); + MasterVolume_Reapply(); + LoadConfig(); + MainTask_Sendmsg(MSG_ID_EC_VOL, app_adc_get_volume(), level, 0); LOG_I("PWR", "periph ready + BT UART recv started"); } @@ -324,8 +408,13 @@ static void PowerOff(void) usb_charging_state = 1; usb_charging_laststate = 1; LOG_I("PWR", "soft-off with Type-C → charge UI"); + Power_QuiesceForCharge("soft-off-charge"); MainTask_Sendmsg(MSG_ID_POWOFF_CHARG, percentage, 1, 0); } + else + { + Power_LogRails("soft-off"); + } } } @@ -349,7 +438,7 @@ void System_PowerOff_Poll(void) } } -/* 电量 <6.2V:提示界面停留后关机 */ +/* 电量 <6.8V:提示界面停留后关机(插着 Type-C 也停负载) */ void System_LowBat_Arm(void) { if (s_lowbat_active) @@ -491,6 +580,7 @@ void Power_Key_Scan() usb_charging_state = 1; usb_charging_laststate = 1; LOG_I("PWR", "boot with USB → charge UI (no logo)"); + Power_QuiesceForCharge("usb-boot-charge"); CurrUIProcress = IdleProcess; MainTask_Sendmsg(MSG_ID_POWOFF_CHARG, percentage, 1, 0); pwr_key_state = KEY_STATE_NONE; diff --git a/Global/Global.h b/Global/Global.h index df1b1c9..a2e9791 100644 --- a/Global/Global.h +++ b/Global/Global.h @@ -180,6 +180,14 @@ void Power_Key_ConsumePress(void); void PowerOff_CutRails(void); void AutoPowerOff_Scan(void); void System_PowerOn(void); +/* Logo 与开机彩灯结束后再开 12V / Dream / 功放(主循环执行,不堵 UI) */ +void System_RequestAudioBringUp(void); +void System_AudioBringUp_Poll(void); +void Power_ChargeIdle_LogPoll(void); +/* 充电页点亮背光数秒后关掉,避免屏幕把电池耗下去 */ +void Power_ChargeBacklightHold(void); +/* 读回各路电源输出电平:main/dream/v12/bt 为 1=开;chg 为 1=充电使能(低有效) */ +void Power_LogRails(const char *where); void System_RequestPowerOff(void); void System_PowerOff_Poll(void); /* 低电量:停声+提示后 10s 关机(主循环 Poll) */ diff --git a/UI/UI_Idle.c b/UI/UI_Idle.c index 6c863a4..dffe70e 100644 --- a/UI/UI_Idle.c +++ b/UI/UI_Idle.c @@ -179,27 +179,16 @@ void IdleProcess(DisplayTaskMessage_Type msg) LCD_WR_REG(0x29); /* Display ON */ s_charge_ui_drawn = false; LCD_BLK_Set(); - /* 模式页出来前不点 8 颗键灯:低电充电时彩灯+功放会把电压拉垮,卡在 Logo */ + /* 彩灯期间必须停在 Logo。此阶段 12V/Dream/功放尚未打开 */ LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_BOOT_LOGO_W, UI0902_BOOT_LOGO_H, UI0902_BOOT_LOGO_ADDR); - rt_thread_mdelay(200); - LoadConfig(); - /* 主音量不在此现场切通道读 ADC(会与扫描任务串通道): - * 待 StartScanTask 后由 MasterVolume_Reapply 统一补发 */ + UI_BootLedShow(); UI_DrawModeSelectScreen(); - app_tm1629_all_on(LED_COLOR_G); + /* 先启动触摸再返回,功放初始化改到主循环,避免 UI 堵在 I2C 里点击无响应 */ StartTouchTask(); StartScanTask(); - /* 充电开机不再跑彩灯,避免 UI 线程堵在模式选择之前;冷开机在触摸已起后再演 */ - if (!usb_charging_state) - UI_BootLedShow(); - /* Dream 上电稍后可能忽略首包 SysEx:再发主音量 + 调音台(保持关机前设置)。 - * 此时扫描任务已启动、模拟开关在轮询,不可现场重读 ADC(会串通道), - * 统一用 MasterVolume_Reapply 取扫描任务维护的最近一次有效音量 */ - rt_thread_mdelay(400); - MasterVolume_Reapply(); - LoadConfig(); + System_RequestAudioBringUp(); Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, level, 1, WHITE, GRAY); break; @@ -291,8 +280,9 @@ void IdleProcess(DisplayTaskMessage_Type msg) LOG_W("UI", "charge flash empty @0x%08lX — flash ui0902", (unsigned long)UI0902_CHARGE_SCREEN_ADDR); } - LCD_BLK_Set(); + Power_ChargeBacklightHold(); s_charge_ui_drawn = true; + Power_LogRails("charge-ui"); } if(usb_charging_state) { @@ -317,6 +307,7 @@ void IdleProcess(DisplayTaskMessage_Type msg) } LCD_WR_PIC_Trans(x, y, g_ChargePctPercent.w, g_ChargePctPercent.h, g_ChargePctPercent.data, BLACK); + Power_ChargeBacklightHold(); } else { @@ -325,6 +316,7 @@ void IdleProcess(DisplayTaskMessage_Type msg) LCD_FillByColor(0, 0, 240, 320, BLACK); BSP_MainPowerEnable(0); s_charge_ui_drawn = false; + Power_LogRails("charge-unplug"); } } break; diff --git a/project/src/main.c b/project/src/main.c index 507e008..0dc6670 100644 --- a/project/src/main.c +++ b/project/src/main.c @@ -91,8 +91,12 @@ int main(void) /* 关机键看门狗:TMR7 + HardFault hook,与主循环/伴奏 ISR 解耦 */ Power_Key_WatchdogInit(); InitMenuUI(); - BSP_HT7178PowerEnable (1); + /* GPIO 默认会拉高蓝牙和 12V。关机充电前先全部关掉,只留主电给屏幕 */ + BSP_DreamCorePowerEnable(0); + BSP_HT7178PowerEnable(0); + BSP_BlueToothPowerEnable(0); BSP_ChargerEnable(1); + Power_LogRails("boot"); CurrUIProcress = IdleProcess; LOG_I("BOOT", "main init done ui=Idle"); /* add user code end 2 */ @@ -106,6 +110,8 @@ int main(void) } /* add user code begin 3 */ Power_Key_Scan(); + System_AudioBringUp_Poll(); + Power_ChargeIdle_LogPoll(); AutoPowerOff_Scan(); System_PowerOff_Poll(); System_LowBat_Poll(); diff --git a/task/task_init.c b/task/task_init.c index ad55d7d..d807511 100644 --- a/task/task_init.c +++ b/task/task_init.c @@ -144,9 +144,12 @@ void TaskMainThread_entry(void* parameter) UITask_Sendmsg(xEvent.MessageType, xEvent.ID, xEvent.HiByte, xEvent.LoByte); break; case MSG_ID_LOW_BAT_TIP: - /* 立即停声,再交给 UI 画提示;主循环 10s 后关机 */ + /* 立即停声并切掉音源/12V/蓝牙,避免提示的 10s 里继续把电池拉过保护电压 */ Stop_AutoBand(); Send_volume(0); + BSP_DreamCorePowerEnable(0); + BSP_HT7178PowerEnable(0); + BSP_BlueToothPowerEnable(0); System_LowBat_Arm(); UITask_Sendmsg(MSG_ID_LOW_BAT_TIP, xEvent.ID, xEvent.HiByte, xEvent.LoByte); break; diff --git a/tools/publish_k1_release.py b/tools/publish_k1_release.py index 4e19e67..4a0b729 100644 --- a/tools/publish_k1_release.py +++ b/tools/publish_k1_release.py @@ -38,7 +38,7 @@ TONE_HDR = PROJ / "project" / "inc" / "ExtFlash_Tone_Addr.h" IAP_DIR = REPO / "升级" / "MCU主控升级" OUT_ROOT = REPO / "tools" / "out" -FW_VER = "0.2.31" +FW_VER = "0.2.35" UI0902_RES_BASE = 0x00100000 BOOT_FLASH_ADDR = 0x08000000 APP_FLASH_ADDR = 0x08008000