fix: keep power key alive on hang; refuse play when tone pack missing

TMR7 high-prio watchdog and fault-loop emergency cut/reset so soft-off still works if the main loop or AutoBand ISR dies; skip start when preset load fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yuquanjun 2026-09-14 20:19:45 +08:00
parent f8aeb4fb7c
commit d06e44bcb3
12 changed files with 207 additions and 65 deletions

View File

@ -142,6 +142,11 @@ void app_log_write(char level, const char *cat, const char *fmt, ...)
va_list ap; va_list ap;
int n; int n;
/* TMR6 1ms ISR 会经 AutoBand NoteOn 回调进来:禁止在中断里 take mutex / 打 RTT */
if (rt_interrupt_get_nest() != 0) {
return;
}
if (level == 'D' && s_debug_level != 'D') { if (level == 'D' && s_debug_level != 'D') {
return; return;
} }
@ -387,7 +392,7 @@ uint8_t app_log_try_command(const char *cmd)
UI_ApplyToneAddress(); UI_ApplyToneAddress();
AutoBandTop1_Stop(); AutoBandTop1_Stop();
StartFlag = 0; StartFlag = 0;
ret = AutoBandTop1_LoadPresetItemFromFlash(0); ret = App_Auto_LoadPresetFromFlash(0);
snprintf(line, sizeof(line), snprintf(line, sizeof(line),
"TONE_LOCAL ret=%d addr=0x%08lX map=BIN2@0x%08lX name=%s count=%d %s\n", "TONE_LOCAL ret=%d addr=0x%08lX map=BIN2@0x%08lX name=%s count=%d %s\n",
ret, (unsigned long)ADDRESS, ret, (unsigned long)ADDRESS,
@ -416,7 +421,7 @@ uint8_t app_log_try_command(const char *cmd)
if (count > 0 && (int)idx >= count) if (count > 0 && (int)idx >= count)
idx = (unsigned)(count - 1); idx = (unsigned)(count - 1);
ParamGuiData[SONG_MODE_PARAM].Current = (uint8_t)idx; ParamGuiData[SONG_MODE_PARAM].Current = (uint8_t)idx;
ret = AutoBandTop1_LoadPresetItemFromFlash((int)idx); ret = App_Auto_LoadPresetFromFlash((int)idx);
snprintf(line, sizeof(line), snprintf(line, sizeof(line),
"TONE_BIN1 ret=%d idx=%u addr=0x%08lX map=BIN1@0x%08lX name=%s count=%d %s\n", "TONE_BIN1 ret=%d idx=%u addr=0x%08lX map=BIN1@0x%08lX name=%s count=%d %s\n",
ret, idx, (unsigned long)ADDRESS, ret, idx, (unsigned long)ADDRESS,
@ -445,7 +450,7 @@ uint8_t app_log_try_command(const char *cmd)
if (count > 0 && (int)idx >= count) if (count > 0 && (int)idx >= count)
idx = (unsigned)(count - 1); idx = (unsigned)(count - 1);
ParamGuiData[EXPRESS_MODE_PARAM].Current = (uint8_t)idx; ParamGuiData[EXPRESS_MODE_PARAM].Current = (uint8_t)idx;
ret = AutoBandTop1_LoadPresetItemFromFlash((int)idx); ret = App_Auto_LoadPresetFromFlash((int)idx);
snprintf(line, sizeof(line), snprintf(line, sizeof(line),
"TONE_BIN2 ret=%d idx=%u addr=0x%08lX map=BIN2@0x%08lX name=%s count=%d %s\n", "TONE_BIN2 ret=%d idx=%u addr=0x%08lX map=BIN2@0x%08lX name=%s count=%d %s\n",
ret, idx, (unsigned long)ADDRESS, ret, idx, (unsigned long)ADDRESS,
@ -474,7 +479,7 @@ uint8_t app_log_try_command(const char *cmd)
if (count > 0 && (int)idx >= count) if (count > 0 && (int)idx >= count)
idx = (unsigned)(count - 1); idx = (unsigned)(count - 1);
ParamGuiData[ALL_MODE_PARAM].Current = (uint8_t)idx; ParamGuiData[ALL_MODE_PARAM].Current = (uint8_t)idx;
ret = AutoBandTop1_LoadPresetItemFromFlash((int)idx); ret = App_Auto_LoadPresetFromFlash((int)idx);
snprintf(line, sizeof(line), snprintf(line, sizeof(line),
"TONE_BIN3 ret=%d idx=%u addr=0x%08lX map=BIN3@0x%08lX name=%s count=%d %s\n", "TONE_BIN3 ret=%d idx=%u addr=0x%08lX map=BIN3@0x%08lX name=%s count=%d %s\n",
ret, idx, (unsigned long)ADDRESS, ret, idx, (unsigned long)ADDRESS,
@ -502,7 +507,7 @@ uint8_t app_log_try_command(const char *cmd)
UI_ApplyToneAddress(); UI_ApplyToneAddress();
AutoBandTop1_Stop(); AutoBandTop1_Stop();
StartFlag = 0; StartFlag = 0;
(void)AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[ALL_MODE_PARAM].Current); (void)App_Auto_LoadPresetFromFlash(ParamGuiData[ALL_MODE_PARAM].Current);
KEY_ID_1629 = 0; KEY_ID_1629 = 0;
PressFlag = 0; PressFlag = 0;
Pick_Handle(); Pick_Handle();

View File

@ -101,7 +101,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)); uint8_t TOUCH_AREA_NUM = (sizeof(Touch_Areas)/sizeof(Touch_AreaTypeDef));
const uint8_t Version[3] = {0,2,10}; /* major.minor.patch — 0.2.10: tone 0914 (BIN3 after 2.bin); autoclose label 关闭 */ const uint8_t Version[3] = {0,2,11}; /* major.minor.patch — 0.2.11: power-key watchdog + refuse play on bad tone pack */
uint8_t Led = 8; uint8_t Led = 8;
bool PressFlag = 0; bool PressFlag = 0;
@ -161,6 +161,7 @@ void BLTask_Sendmsg(uint16_t ID, uint16_t ID2, uint16_t HiByte, uint16_t LoByte)
#define PWR_ON_HOLD_MS 3000 /* 关机态长按 3s → 开机 */ #define PWR_ON_HOLD_MS 3000 /* 关机态长按 3s → 开机 */
#define PWR_OFF_HOLD_MS 2000 /* 开机态长按 2s → 关机 */ #define PWR_OFF_HOLD_MS 2000 /* 开机态长按 2s → 关机 */
#define PWR_OFF_GRACE_MS 1500 /* 请求优雅关机后,超时仍未切轨则紧急断电+复位 */
typedef enum typedef enum
@ -176,10 +177,37 @@ static uint32_t pwr_press_tick = 0;
/* 当前开关机状态UI_Idle.c 等 extern 引用) */ /* 当前开关机状态UI_Idle.c 等 extern 引用) */
bool powon = false; bool powon = false;
/* 电源轨是否已切断优雅关机与紧急关机共用ISR 依此判断是否还需强切) */
static volatile uint8_t s_pwr_rails_cut = 0;
/* TMR7关机长按已触发请求后的紧急倒计时ms */
static volatile uint16_t s_pwr_off_grace_ms = 0;
/* ==================== 开机/关机动作 ==================== */ /* ==================== 开机/关机动作 ==================== */
/* 仅 GPIO/背光:可在 ISR / HardFault 中调用,禁止 RTOS/Flash/日志 */
void PowerOff_CutRails(void)
{
s_pwr_rails_cut = 1u;
powon = false;
LCD_BLK_Clr();
BSP_MainPowerEnable(0);
BSP_DreamCorePowerEnable(0);
BSP_HT7178PowerEnable(0);
BSP_BlueToothPowerEnable(0);
}
static void PowerOff_EmergencyReset(void)
{
PowerOff_CutRails();
/* 主循环已死时无法画充电页:复位后按 USB 状态进充电/待机 */
nvic_system_reset();
}
void System_PowerOn(void) void System_PowerOn(void)
{ {
LOG_I("PWR", "power_on begin"); LOG_I("PWR", "power_on begin");
s_pwr_rails_cut = 0u;
s_pwr_off_grace_ms = 0u;
/* 控制电源硬件;蓝牙按 NVM/系统设置开关恢复,勿强制常开 */ /* 控制电源硬件;蓝牙按 NVM/系统设置开关恢复,勿强制常开 */
BSP_MainPowerEnable(1); BSP_MainPowerEnable(1);
BSP_DreamCorePowerEnable(1); BSP_DreamCorePowerEnable(1);
@ -213,6 +241,7 @@ static void PowerOff(void)
LOG_I("PWR", "power_off begin"); LOG_I("PWR", "power_off begin");
powon = false; /* 更新关机标志 */ powon = false; /* 更新关机标志 */
s_pwr_off_grace_ms = 0u; /* 主路径已接管,取消紧急倒计时 */
StopFullTask(); StopFullTask();
/* 关机前把当前调音台推子与蓝牙开关写入 NVM保证再次开机保持 */ /* 关机前把当前调音台推子与蓝牙开关写入 NVM保证再次开机保持 */
@ -234,13 +263,9 @@ static void PowerOff(void)
app_tm1629_all_off(); app_tm1629_all_off();
app_tm1617_off(); app_tm1617_off();
/* 关掉主电源/音源/功放/蓝牙MCU 仍跑以便长按开机与 Type-C 检测 */ /* BT 先留窗口转发已排队 ACK再切全部电源轨 */
BSP_MainPowerEnable(0);
BSP_DreamCorePowerEnable(0);
BSP_HT7178PowerEnable(0);
/* BT 最后关:给已排队的 UART4 ACK如 05 00留出模组转发窗口 */
rt_thread_mdelay(30); rt_thread_mdelay(30);
BSP_BlueToothPowerEnable(0); PowerOff_CutRails();
CurrUIProcress = IdleProcess; CurrUIProcress = IdleProcess;
MainTask_Sendmsg(MSG_ID_POWER_OFF, 0, 0, 0); MainTask_Sendmsg(MSG_ID_POWER_OFF, 0, 0, 0);
LOG_I("PWR", "power_off done (soft-off)"); LOG_I("PWR", "power_off done (soft-off)");
@ -271,6 +296,9 @@ static volatile uint8_t s_sys_poweroff_req = 0;
void System_RequestPowerOff(void) void System_RequestPowerOff(void)
{ {
s_sys_poweroff_req = 1; s_sys_poweroff_req = 1;
/* 主循环若已卡死TMR7 紧急倒计时仍会强切电源 */
if (s_pwr_off_grace_ms == 0u && !s_pwr_rails_cut)
s_pwr_off_grace_ms = PWR_OFF_GRACE_MS;
} }
void System_PowerOff_Poll(void) void System_PowerOff_Poll(void)
{ {
@ -282,6 +310,77 @@ void System_PowerOff_Poll(void)
} }
} }
/*
* TMR7 1ms TMR6
*
*/
void Power_Key_IsrTick(void)
{
static uint16_t isr_hold_ms = 0;
static uint8_t isr_fired = 0;
flag_status st = BSP_GetPowerKey();
if (st == KEY_PRESS_LEVEL)
{
if (isr_hold_ms < 60000u)
isr_hold_ms++;
}
else
{
isr_hold_ms = 0;
isr_fired = 0;
}
/* 仅处理「开机态关机」;开机仍由主循环负责(需完整外设初始化) */
if (powon && !isr_fired && isr_hold_ms >= PWR_OFF_HOLD_MS)
{
isr_fired = 1;
System_RequestPowerOff();
}
if (s_pwr_off_grace_ms > 0u)
{
s_pwr_off_grace_ms--;
if (s_pwr_off_grace_ms == 0u && !s_pwr_rails_cut)
PowerOff_EmergencyReset();
}
}
/* HardFault / MemManage / BusFault / UsageFault死循环中仍可长按关机 */
void Power_Key_FaultLoop(void)
{
uint32_t hold = 0;
for (;;)
{
if (BSP_GetPowerKey() == KEY_PRESS_LEVEL)
{
hold++;
if (hold >= PWR_OFF_HOLD_MS)
{
PowerOff_EmergencyReset();
}
}
else
{
hold = 0;
}
Delay_us(1000);
}
}
static rt_err_t Power_HardFault_Hook(void *context)
{
(void)context;
Power_Key_FaultLoop();
return -RT_ERROR; /* 不可达 */
}
void Power_Key_WatchdogInit(void)
{
rt_hw_exception_install(Power_HardFault_Hook);
wk_tmr7_pwrkey_init();
}
void Power_Key_Scan() void Power_Key_Scan()
{ {
flag_status status = BSP_GetPowerKey(); flag_status status = BSP_GetPowerKey();
@ -340,19 +439,13 @@ void Power_Key_Scan()
} }
holdtick = now - pwr_press_tick; holdtick = now - pwr_press_tick;
/* 用 powon 区分:关机长按 3s 开机,开机长按 2s 关机 */ /* 关机长按 3s 开机;开机态关机改由 TMR7 ISR主循环卡死仍可关 */
if(powon == false && holdtick >= PWR_ON_HOLD_MS) if(powon == false && holdtick >= PWR_ON_HOLD_MS)
{ {
LOG_I("PWR", "key power_on hold=%u", (unsigned)holdtick); LOG_I("PWR", "key power_on hold=%u", (unsigned)holdtick);
PowerOn(); PowerOn();
pwr_key_state = KEY_STATE_NONE; pwr_key_state = KEY_STATE_NONE;
} }
else if(powon == true && holdtick >= PWR_OFF_HOLD_MS)
{
LOG_I("PWR", "key power_off hold=%u", (unsigned)holdtick);
PowerOff();
pwr_key_state = KEY_STATE_NONE;
}
break; break;
case KEY_STATE_NONE: case KEY_STATE_NONE:
@ -814,6 +907,15 @@ void Pick_Handle()
uint8_t note_cnt = 0; uint8_t note_cnt = 0;
uint8_t chord_id = KEY_ID_1629; uint8_t chord_id = KEY_ID_1629;
/* 空库/加载失败时禁止起奏:否则 TMR6 ISR 内 AutoBand 可能 HardFault
* LCD Power_Key_Scan RESET */
if (!App_Auto_IsPresetReady())
{
LOG_E("pick", "abort: preset not ready tab=%u addr=0x%08X",
(unsigned)mGuiData[GUI_TAB_INDEX].Current, (unsigned)ADDRESS);
return;
}
/* 左手未触发和弦板(或落在拍速/停止键)时:拨片默认发当前调一级大和弦伴奏; /* 左手未触发和弦板(或落在拍速/停止键)时:拨片默认发当前调一级大和弦伴奏;
* */ * */
if (mGuiData[GUI_TAB_INDEX].Current != 2 && if (mGuiData[GUI_TAB_INDEX].Current != 2 &&

View File

@ -166,6 +166,10 @@ extern uint8_t KEY_ID_1629;
extern bool powon; extern bool powon;
void Power_Key_Scan(void); void Power_Key_Scan(void);
void Power_Key_IsrTick(void);
void Power_Key_FaultLoop(void);
void Power_Key_WatchdogInit(void);
void PowerOff_CutRails(void);
void AutoPowerOff_Scan(void); void AutoPowerOff_Scan(void);
void System_PowerOn(void); void System_PowerOn(void);
void System_RequestPowerOff(void); void System_RequestPowerOff(void);

View File

@ -416,6 +416,31 @@ static const char *ToneFlashMapBank(uint32_t abs)
static uint32_t s_flash_rd_last_base = 0xFFFFFFFFu; static uint32_t s_flash_rd_last_base = 0xFFFFFFFFu;
static uint16_t s_flash_rd_log_cnt = 0; static uint16_t s_flash_rd_log_cnt = 0;
/* 最近一次 LoadPreset 是否成功;失败时禁止拨片起奏(防空库 + TMR6 ISR 崩) */
static volatile uint8_t s_preset_ready = 0;
int App_Auto_LoadPresetFromFlash(int presetIndex)
{
int ret = AutoBandTop1_LoadPresetItemFromFlash(presetIndex);
if (ret == 0)
{
const char *name = AutoBandTop1_GetPresetName();
int count = AutoBandTop1_GetPresetItemCount();
s_preset_ready = (count > 0 && name != NULL && name[0] != '\0') ? 1u : 0u;
}
else
{
s_preset_ready = 0u;
AutoBandTop1_Stop();
StartFlag = 0;
}
return ret;
}
uint8_t App_Auto_IsPresetReady(void)
{
return s_preset_ready;
}
static int Func_CallBack_ReadFlash(int address,int length,uint8_t* pOutput) static int Func_CallBack_ReadFlash(int address,int length,uint8_t* pOutput)
{ {
@ -468,7 +493,7 @@ void App_Auto_Init(void)
AutoBandTop1_RegisterReadFlashCallback(Func_CallBack_ReadFlash); AutoBandTop1_RegisterReadFlashCallback(Func_CallBack_ReadFlash);
m_presetCount = AutoBandTop1_GetPresetItemCount(); m_presetCount = AutoBandTop1_GetPresetItemCount();
int ret = AutoBandTop1_LoadPresetItemFromFlash(0); int ret = App_Auto_LoadPresetFromFlash(0);
if (ret != 0) if (ret != 0)
{ {
uint8_t hdr[16]; uint8_t hdr[16];

View File

@ -8,9 +8,14 @@
#ifndef APP_AUTO_H_ #ifndef APP_AUTO_H_
#define APP_AUTO_H_ #define APP_AUTO_H_
#include "mymidififo1.h" #include "mymidififo1.h"
#include <stdint.h>
extern void App_Auto_Init(void); extern void App_Auto_Init(void);
/* 统一加载入口:记录成功/失败,失败时 Stop避免空库起奏进 ISR 崩溃 */
int App_Auto_LoadPresetFromFlash(int presetIndex);
uint8_t App_Auto_IsPresetReady(void);
extern MidiFifoSeq_t m_MidiSendFifo; extern MidiFifoSeq_t m_MidiSendFifo;
#endif /* APP_AUTO_H_ */ #endif /* APP_AUTO_H_ */

View File

@ -180,11 +180,11 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
UI_ApplyToneAddress(); UI_ApplyToneAddress();
int ret = 0; int ret = 0;
if (tab == 0) if (tab == 0)
ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[ALL_MODE_PARAM].Current); ret = App_Auto_LoadPresetFromFlash(ParamGuiData[ALL_MODE_PARAM].Current);
else if (mGuiData[GUI_AUTOBAND_SW].Current) else if (mGuiData[GUI_AUTOBAND_SW].Current)
ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[EXPRESS_MODE_PARAM].Current); ret = App_Auto_LoadPresetFromFlash(ParamGuiData[EXPRESS_MODE_PARAM].Current);
else else
ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[SONG_MODE_PARAM].Current); ret = App_Auto_LoadPresetFromFlash(ParamGuiData[SONG_MODE_PARAM].Current);
if (ret != 0) if (ret != 0)
LOG_E("tone", "load preset failed tab=%d sw=%d ret=%d addr=0x%08X", LOG_E("tone", "load preset failed tab=%d sw=%d ret=%d addr=0x%08X",
tab, mGuiData[GUI_AUTOBAND_SW].Current, ret, (unsigned)ADDRESS); tab, mGuiData[GUI_AUTOBAND_SW].Current, ret, (unsigned)ADDRESS);

View File

@ -170,7 +170,7 @@ void UI_ReloadTonePreset(void)
/* 万能:和弦走向 */ /* 万能:和弦走向 */
if (mGuiData[GUI_TAB_INDEX].Current == 0) if (mGuiData[GUI_TAB_INDEX].Current == 0)
{ {
int ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[ALL_MODE_PARAM].Current); int ret = App_Auto_LoadPresetFromFlash(ParamGuiData[ALL_MODE_PARAM].Current);
if (ret != 0) if (ret != 0)
{ {
uint8_t hdr[16]; uint8_t hdr[16];
@ -197,7 +197,7 @@ void UI_ReloadTonePreset(void)
local->Max = (LOCAL_SONG_COUNT > 0) ? (uint16_t)(LOCAL_SONG_COUNT - 1) : 0; local->Max = (LOCAL_SONG_COUNT > 0) ? (uint16_t)(LOCAL_SONG_COUNT - 1) : 0;
if (local->Current > local->Max) if (local->Current > local->Max)
local->Current = local->Max; local->Current = local->Max;
int ret = AutoBandTop1_LoadPresetItemFromFlash(local->Current); int ret = App_Auto_LoadPresetFromFlash(local->Current);
if (ret != 0) if (ret != 0)
LOG_E("tone", "load local song idx=%d failed ret=%d addr=0x%08X map=BIN2@0x%08X", LOG_E("tone", "load local song idx=%d failed ret=%d addr=0x%08X map=BIN2@0x%08X",
local->Current, ret, (unsigned)ADDRESS, local->Current, ret, (unsigned)ADDRESS,
@ -217,7 +217,7 @@ void UI_ReloadTonePreset(void)
return; return;
} }
{ {
int ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[SONG_MODE_PARAM].Current); int ret = App_Auto_LoadPresetFromFlash(ParamGuiData[SONG_MODE_PARAM].Current);
LOG_I("tone", "load rhythm idx=%d ret=%d name=%s addr=0x%08X map=BIN1@0x%08X %s", LOG_I("tone", "load rhythm idx=%d ret=%d name=%s addr=0x%08X map=BIN1@0x%08X %s",
ParamGuiData[SONG_MODE_PARAM].Current, ret, ParamGuiData[SONG_MODE_PARAM].Current, ret,
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?", AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?",

View File

@ -41,6 +41,9 @@ void wk_tmr6_1ms_init(void);
void wk_tmr6_1ms_tick(void); void wk_tmr6_1ms_tick(void);
uint32_t wk_tmr6_tick_get(void); uint32_t wk_tmr6_tick_get(void);
/* TMR7 1ms关机键看门狗优先级高于 TMR6主循环卡死仍可关 */
void wk_tmr7_pwrkey_init(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -30,7 +30,9 @@
/* private includes ----------------------------------------------------------*/ /* private includes ----------------------------------------------------------*/
/* add user code begin private includes */ /* add user code begin private includes */
/* 关机键看门狗:与 Global.c 解耦声明,避免 int.c 拉全量 includes */
void Power_Key_IsrTick(void);
void Power_Key_FaultLoop(void);
/* add user code end private includes */ /* add user code end private includes */
/* private typedef -----------------------------------------------------------*/ /* private typedef -----------------------------------------------------------*/
@ -110,16 +112,7 @@ void NMI_Handler(void)
*/ */
void MemManage_Handler(void) void MemManage_Handler(void)
{ {
/* add user code begin MemoryManagement_IRQ 0 */ Power_Key_FaultLoop();
/* add user code end MemoryManagement_IRQ 0 */
/* go to infinite loop when memory manage exception occurs */
while (1)
{
/* add user code begin W1_MemoryManagement_IRQ 0 */
/* add user code end W1_MemoryManagement_IRQ 0 */
}
} }
/** /**
@ -129,16 +122,7 @@ void MemManage_Handler(void)
*/ */
void BusFault_Handler(void) void BusFault_Handler(void)
{ {
/* add user code begin BusFault_IRQ 0 */ Power_Key_FaultLoop();
/* add user code end BusFault_IRQ 0 */
/* go to infinite loop when bus fault exception occurs */
while (1)
{
/* add user code begin W1_BusFault_IRQ 0 */
/* add user code end W1_BusFault_IRQ 0 */
}
} }
/** /**
@ -148,16 +132,7 @@ void BusFault_Handler(void)
*/ */
void UsageFault_Handler(void) void UsageFault_Handler(void)
{ {
/* add user code begin UsageFault_IRQ 0 */ Power_Key_FaultLoop();
/* add user code end UsageFault_IRQ 0 */
/* go to infinite loop when usage fault exception occurs */
while (1)
{
/* add user code begin W1_UsageFault_IRQ 0 */
/* add user code end W1_UsageFault_IRQ 0 */
}
} }
/** /**
@ -241,6 +216,15 @@ void TMR6_GLOBAL_IRQHandler(void)
//rt_os_tick_callback(); //rt_os_tick_callback();
} }
/**
* @brief TMR7 TMR6
*/
void TMR7_GLOBAL_IRQHandler(void)
{
tmr_flag_clear(TMR7, TMR_OVF_FLAG);
Power_Key_IsrTick();
}
/* add user code begin 1 */ /* add user code begin 1 */
/* add user code end 1 */ /* add user code end 1 */

View File

@ -88,6 +88,8 @@ int main(void)
drv_nvm_init(); drv_nvm_init();
TaskInit(); TaskInit();
timer_init(); timer_init();
/* 关机键看门狗TMR7 + HardFault hook与主循环/伴奏 ISR 解耦 */
Power_Key_WatchdogInit();
InitMenuUI(); InitMenuUI();
BSP_HT7178PowerEnable (1); BSP_HT7178PowerEnable (1);
BSP_ChargerEnable(1); BSP_ChargerEnable(1);

View File

@ -174,3 +174,16 @@ void wk_tmr6_1ms_init(void)
tmr_counter_enable(TMR6, TRUE); tmr_counter_enable(TMR6, TRUE);
} }
/**
* @brief TMR7 1ms 1 TMR6=5 /
*/
void wk_tmr7_pwrkey_init(void)
{
crm_periph_clock_enable(CRM_TMR7_PERIPH_CLOCK, TRUE);
tmr_base_init(TMR7, 999, 239);
tmr_flag_clear(TMR7, TMR_OVF_FLAG);
tmr_interrupt_enable(TMR7, TMR_OVF_INT, TRUE);
nvic_irq_enable(TMR7_GLOBAL_IRQn, 1, 0);
tmr_counter_enable(TMR7, TRUE);
}

View File

@ -38,7 +38,7 @@ TONE_HDR = PROJ / "project" / "inc" / "ExtFlash_Tone_Addr.h"
IAP_DIR = REPO / "升级" / "MCU主控升级" IAP_DIR = REPO / "升级" / "MCU主控升级"
OUT_ROOT = REPO / "tools" / "out" OUT_ROOT = REPO / "tools" / "out"
FW_VER = "0.2.10" FW_VER = "0.2.11"
UI0902_RES_BASE = 0x00100000 UI0902_RES_BASE = 0x00100000
BOOT_FLASH_ADDR = 0x08000000 BOOT_FLASH_ADDR = 0x08000000
APP_FLASH_ADDR = 0x08008000 APP_FLASH_ADDR = 0x08008000
@ -135,12 +135,11 @@ def main() -> None:
raise SystemExit(f"missing Boot bin: {BOOT_BIN}") raise SystemExit(f"missing Boot bin: {BOOT_BIN}")
if not EXE_BIN.is_file(): if not EXE_BIN.is_file():
raise SystemExit(f"missing MCU bin: {EXE_BIN}") raise SystemExit(f"missing MCU bin: {EXE_BIN}")
if not TONE_BIN.is_file(): tone_bin = TONE_BIN
# fallback legacy alias written by packer if not tone_bin.is_file():
legacy = PROJ / "tools" / "out" / "extflash_tone_0903.bin" legacy = PROJ / "tools" / "out" / "extflash_tone_0903.bin"
if legacy.is_file(): if legacy.is_file():
global TONE_BIN tone_bin = legacy
TONE_BIN = legacy
else: else:
raise SystemExit(f"missing tone pack: {TONE_BIN} (run pack_extflash_tone_0903.py)") raise SystemExit(f"missing tone pack: {TONE_BIN} (run pack_extflash_tone_0903.py)")
if not UI0902_BIN.is_file(): if not UI0902_BIN.is_file():
@ -165,7 +164,7 @@ def main() -> None:
shutil.rmtree(pkg) shutil.rmtree(pkg)
pkg.mkdir(parents=True) pkg.mkdir(parents=True)
tone_data = TONE_BIN.read_bytes() tone_data = tone_bin.read_bytes()
verify_tone_layout(tone_data) verify_tone_layout(tone_data)
ui_data = UI0902_BIN.read_bytes() ui_data = UI0902_BIN.read_bytes()
if len(ui_data) < 1024: if len(ui_data) < 1024: