From 68e3a37883629da79098d89b8cfac6d863036baf Mon Sep 17 00:00:00 2001 From: yuquanjun Date: Mon, 31 Aug 2026 08:20:24 +0800 Subject: [PATCH] Fix mode-select layout/battery margins and enable reliable post-flash boot. Co-authored-by: Cursor --- AT32F403ARCT7_BOOT/project/src/main.c | 10 +++-- Global/Global.c | 20 +++++++++- Global/Global.h | 4 +- UI/UI_Idle.c | 33 ++++++++++------ UI/UI_global.c | 2 +- UI/UI_global.h | 4 +- device/LCD_ILI9341/Drv_ILI9341_Lcd_App.c | 49 ++++++++++++++++-------- tools/flash_app.bat | 16 +++++--- tools/rtt_lcd_capture.py | 15 ++++++-- 9 files changed, 111 insertions(+), 42 deletions(-) diff --git a/AT32F403ARCT7_BOOT/project/src/main.c b/AT32F403ARCT7_BOOT/project/src/main.c index 3b317b6..ccedea6 100644 --- a/AT32F403ARCT7_BOOT/project/src/main.c +++ b/AT32F403ARCT7_BOOT/project/src/main.c @@ -130,13 +130,17 @@ int main(void) TM1617_GPIO_Init(); - wk_delay_ms(1000); - + /* 短暂等待总线稳定;默认跳转 App。 + * 仅当开机时按住 KEY_MAIN_A 才进入 USB 升级模式。 + * (旧逻辑:仅 KEY_NULL 才跳 App,复位后按键误读会永久卡在 Boot 黑屏) */ + wk_delay_ms(50); TM1617KeyValue = TM1617_ScanFkey(); - if(TM1617KeyValue == 4) + if (TM1617KeyValue != KEY_MAIN_A) { JumpToApplication(); + /* 若 App 向量无效则继续走升级模式 */ } + /* init spi1 function. */ BSP_MainPowerEnable(1); wk_spi1_init(); diff --git a/Global/Global.c b/Global/Global.c index 1f7f0fd..e9d15dd 100644 --- a/Global/Global.c +++ b/Global/Global.c @@ -155,7 +155,7 @@ static uint32_t pwr_press_tick = 0; bool powon = false; /* ==================== 寮鏈/鍏虫満鍔ㄤ綔 ==================== */ -static void PowerOn(void) +void System_PowerOn(void) { /* 鎺у埗鐢垫簮纭欢 */ BSP_MainPowerEnable(1); @@ -173,6 +173,11 @@ static void PowerOn(void) MainTask_Sendmsg(MSG_ID_POWER_ON,0,0,0); } +static void PowerOn(void) +{ + System_PowerOn(); +} + static void PowerOff(void) { powon = false; /* 鏇存柊鍏虫満鏍囧織 */ @@ -202,6 +207,19 @@ void Power_Key_Scan() uint32_t now = rt_tick_get(); uint32_t holdtick = 0; + /* 澶嶄綅/鐑у綍鍚庤嚜鍔ㄥ紑鏈轰竴娆★紝閬垮厤榛戝睆骞茬瓑闀挎寜锛涙甯稿叧鏈哄悗涓嬬數鍐嶄笂鐢典粛璧版璺緞 */ + if (powon == false && pwr_key_state == KEY_STATE_IDLE && pwr_press_tick == 0) + { + static uint8_t s_auto_poweron_pending = 1; + if (s_auto_poweron_pending) + { + s_auto_poweron_pending = 0; + PowerOn(); + pwr_key_state = KEY_STATE_NONE; /* 蹇界暐寮鏈虹灛闂村彲鑳芥畫鐣欑殑鎸夐敭鐢靛钩 */ + return; + } + } + switch(pwr_key_state) { case KEY_STATE_IDLE: diff --git a/Global/Global.h b/Global/Global.h index 137a010..f23f7aa 100644 --- a/Global/Global.h +++ b/Global/Global.h @@ -164,6 +164,8 @@ extern rt_timer_t OutTime_Stop_timer; extern uint8_t KEY_ID_1629; extern bool powon; +void Power_Key_Scan(void); +void System_PowerOn(void); extern uint8_t Led; extern bool PressFlag; @@ -194,8 +196,6 @@ extern void (*CurrUIProcress)(DisplayTaskMessage_Type xEvent); void Stop_AutoBand(); -void Power_Key_Scan(); - static void ShowPowerOn(); void GET_ParamNum_Str(int16_t NUM, uint8_t ValidLen, char* Str, uint8_t hasSign); diff --git a/UI/UI_Idle.c b/UI/UI_Idle.c index aa686fc..9b56615 100644 --- a/UI/UI_Idle.c +++ b/UI/UI_Idle.c @@ -22,7 +22,13 @@ void RGB_Y_TO_G() #define UI_MODE_BG_COLOR 0x1925 #define UI_MODE_LINE_COLOR DARKBLUE #define UI_MODE_TEXT_COLOR 0xFFFF -#define UI_MODE_FONT_SIZE 16 +/* PDF 鏍囨敞 MiSans-Medium 21锛涘瓧搴撴棤 21锛岀敤 28 涓 40x30 鍥炬爣姣斾緥鎺ヨ繎鏍囨敞绋 */ +#define UI_MODE_FONT_SIZE 28 +#define UI_MODE_ICON_W 40 +#define UI_MODE_ICON_H 30 +#define UI_MODE_ICON_TEXT_GAP 8 +/* 姹夊瓧澧ㄥ績鐣ュ亸涓婏紱涓嬬Щ涓庡浘鏍囧厜蹇冨钩榻愶紙杩囧ぇ鏄撴樉寰楁枃瀛楀亸涓嬶級 */ +#define UI_MODE_TEXT_OPTICAL_DY 2 /* 妯″紡閫夋嫨椤电劍鐐癸細0=涓囪兘 1=鏅 2=涓撲笟锛岄粯璁ら変腑涓囪兘锛堜笌瑙勮寖涓鑷达級 */ static uint8_t s_mode_select_focus = 0; @@ -34,8 +40,13 @@ static void UI_DrawModeSelectButton(uint16_t y, const uint8_t *text, const uint16_t btn_h = 87; const uint16_t btn_r = 10; const uint16_t btn_x = (240 - btn_w) / 2; - uint16_t text_y = y + (btn_h - UI_MODE_FONT_SIZE) / 2; - uint16_t text_x; + const uint16_t text_w = (uint16_t)(4 * UI_MODE_FONT_SIZE); + const uint16_t group_w = (uint16_t)(UI_MODE_ICON_W + UI_MODE_ICON_TEXT_GAP + text_w); + const uint16_t group_x = (uint16_t)(btn_x + (btn_w - group_w) / 2); + const uint16_t mid_y = (uint16_t)(y + btn_h / 2); + const uint16_t icon_y = (uint16_t)(mid_y - UI_MODE_ICON_H / 2); + const uint16_t text_y = (uint16_t)(mid_y - UI_MODE_FONT_SIZE / 2 + UI_MODE_TEXT_OPTICAL_DY); + const uint16_t text_x = (uint16_t)(group_x + UI_MODE_ICON_W + UI_MODE_ICON_TEXT_GAP); if (focused) { @@ -47,24 +58,24 @@ static void UI_DrawModeSelectButton(uint16_t y, const uint8_t *text, LCD_FillRoundRect(btn_x, y, btn_w, btn_h, btn_r, COLOR_NORMAL_BG); } - /* 鍙犲姞缁樺埗鏂囧瓧锛岄伩鍏嶅湪娓愬彉搴曚笂鎵撳嚭瀹炲績鑹插潡 */ - text_x = LCD_ShowChinese_AutoAlign( - btn_x, btn_x + btn_w, + LCD_WR_PIC_Trans(group_x, icon_y, UI_MODE_ICON_W, UI_MODE_ICON_H, icon, BLACK); + LCD_ShowChinese_AutoAlign( + text_x, (uint16_t)(text_x + text_w - 1), text_y, text, - LCD_ALIGN_CENTER, + LCD_ALIGN_LEFT, UI_MODE_TEXT_COLOR, BLACK, 1, UI_MODE_FONT_SIZE ); - LCD_WR_PIC_Trans(text_x - 45, text_y - 5, 40, 30, icon, BLACK); } void UI_DrawModeSelectScreen(void) { UI_ClearFocus(); s_mode_select_focus = 0; + pCurrentTouch_Area = Touch_ModeSelect_Areas; LCD_FillByColor(0, 0, 240, 320, BLACK); label_top(); @@ -212,10 +223,10 @@ void IdleProcess(DisplayTaskMessage_Type msg) case MSG_ID_TOUCH: for(uint8_t k=0; k= pCurrentTouch_Area[k].x_min && msg.HiByte <= pCurrentTouch_Area[k].x_max && - msg.LoByte >= pCurrentTouch_Area[k].y_min && msg.LoByte <= pCurrentTouch_Area[k].y_max ) + if( msg.HiByte >= Touch_ModeSelect_Areas[k].x_min && msg.HiByte <= Touch_ModeSelect_Areas[k].x_max && + msg.LoByte >= Touch_ModeSelect_Areas[k].y_min && msg.LoByte <= Touch_ModeSelect_Areas[k].y_max ) { - Touch_Mode_Select_Action(pCurrentTouch_Area[k].Flag,pCurrentTouch_Area[k].ID,k); + Touch_Mode_Select_Action(Touch_ModeSelect_Areas[k].Flag,Touch_ModeSelect_Areas[k].ID,k); break; } } diff --git a/UI/UI_global.c b/UI/UI_global.c index 05b8f74..ad3da65 100644 --- a/UI/UI_global.c +++ b/UI/UI_global.c @@ -156,7 +156,7 @@ void label_top() const uint16_t btn_color = /*DARKLGRAY*/0x2988; // 娣辩伆锟????? //LCD_FillByColor(0,0,240,25,BLACK); //LCD_WR_PIC(5,0,12,20,gImage_bar); - Draw_Volume_Bar(5, 5, level, 1, WHITE, GRAY); + Draw_Volume_Bar(8, 5, level, 1, WHITE, GRAY); LCD_DrawLine(0, 26, 240, 26, btn_color); Show_BL_Icon(mGuiData[GUI_BL_SW].Current); Show_Battery_Icon(usb_charging_state); diff --git a/UI/UI_global.h b/UI/UI_global.h index 8bd7d26..a7be73c 100644 --- a/UI/UI_global.h +++ b/UI/UI_global.h @@ -28,9 +28,11 @@ void CallUI_RestoreSelect(void); #define UI_STATUS_BAR_H 26 -#define UI_STATUS_BATTERY_X 180 +/* 鐢甸噺缁勫湪 Draw_Battery_Icon 鍐呮寜鍙冲榻愰噸绠楋紱姝ゅ间负鍏佽鐨勬渶宸﹁捣鐐 */ +#define UI_STATUS_BATTERY_X 150 #define UI_STATUS_BATTERY_H 11 #define UI_STATUS_BATTERY_Y ((UI_STATUS_BAR_H - UI_STATUS_BATTERY_H) / 2) +#define UI_STATUS_BATTERY_RIGHT_MARGIN 8 #define UI_FOCUS_NONE 0xFF void UI_ClearFocus(void); diff --git a/device/LCD_ILI9341/Drv_ILI9341_Lcd_App.c b/device/LCD_ILI9341/Drv_ILI9341_Lcd_App.c index 389e48a..1310271 100644 --- a/device/LCD_ILI9341/Drv_ILI9341_Lcd_App.c +++ b/device/LCD_ILI9341/Drv_ILI9341_Lcd_App.c @@ -150,14 +150,13 @@ void LCD_WR_PIC(uint16_t x, uint16_t y, uint16_t length, uint16_t width, const u } } -/* 璺宠繃 key_color 鍍忕礌锛岀敤浜庡浘鏍囬忔槑搴曪紙甯歌 key=BLACK锛 */ +/* 璺宠繃杩戦粦鑹插儚绱狅紙鍥炬爣瀵煎嚭搴曡壊甯镐负 0x0000/0x0001/0x0022锛岄潪绾 BLACK锛 */ void LCD_WR_PIC_Trans(uint16_t x, uint16_t y, uint16_t length, uint16_t width, const uint8_t data[], uint16_t key_color) { uint32_t total_pixels = (uint32_t)length * width; - uint8_t key_h = (uint8_t)(key_color >> 8); - uint8_t key_l = (uint8_t)(key_color & 0xFF); uint32_t i; + (void)key_color; if (total_pixels == 0) return; @@ -166,11 +165,18 @@ void LCD_WR_PIC_Trans(uint16_t x, uint16_t y, uint16_t length, uint16_t width, { uint8_t hi = data[i * 2]; uint8_t lo = data[i * 2 + 1]; - if (hi == key_h && lo == key_l) + uint16_t c = (uint16_t)((hi << 8) | lo); + uint8_t r5 = (uint8_t)((c >> 11) & 0x1F); + uint8_t g6 = (uint8_t)((c >> 5) & 0x3F); + uint8_t b5 = (uint8_t)(c & 0x1F); + + /* 杩戦粦瑙嗕负閫忔槑锛岄伩鍏嶅浘鏍囬粦搴曟柟鍧 */ + if (r5 <= 1 && g6 <= 2 && b5 <= 2) continue; + LCD_DrawPoint((uint16_t)(x + (i % length)), (uint16_t)(y + (i / length)), - (uint16_t)((hi << 8) | lo)); + c); } } @@ -1794,11 +1800,14 @@ void Draw_Battery_Icon(uint16_t x, uint16_t y, uint8_t battery_percent,uint8_t s uint8_t round_r = 2 * scale; uint8_t stroke = 1 * scale; uint16_t fill_gap = 2 * scale; - uint8_t text_size = 16 * scale; /* 16px ASCII 瀛椾綋娓叉煋鍙潬锛13px 浣嶅浘涓庨┍鍔ㄤ笉鍖归厤浼氫贡鐮 */ + /* PDF 鏍囨敞 7.5锛屼絾 8px ASCII 浣嶅浘涔辩爜锛涚敤 16px 骞舵暣缁勫彸瀵归綈锛岄伩鍏嶅乏鍙宠瑁 */ + uint8_t text_size = 16 * scale; uint8_t status_bar_h = 26 * scale; uint8_t Info[40]; uint16_t pole_w = 2 * scale; uint16_t pole_h = 5 * scale; + uint16_t gap = 6 * scale; + uint16_t right_margin = 14 * scale; uint16_t pole_x; uint16_t pole_y; uint16_t inner_w; @@ -1806,6 +1815,9 @@ void Draw_Battery_Icon(uint16_t x, uint16_t y, uint8_t battery_percent,uint8_t s uint16_t fill_w; uint16_t text_x; uint16_t text_y; + uint16_t text_w; + uint16_t group_w; + uint16_t bat_x = x; uint16_t clear_h; if(battery_percent > 100) @@ -1813,18 +1825,26 @@ void Draw_Battery_Icon(uint16_t x, uint16_t y, uint8_t battery_percent,uint8_t s battery_percent = 100; } + sprintf((char*)Info, "%d%%", battery_percent); + text_w = (uint16_t)(strlen((char*)Info) * (text_size / 2)); + group_w = (uint16_t)(bat_w + pole_w + gap + text_w); + if (group_w + right_margin < 240) + bat_x = (uint16_t)(240 - right_margin - group_w); + if (bat_x < x) + bat_x = x; + clear_h = (bat_h > text_size) ? bat_h : text_size; if(status_bar_h > clear_h) { clear_h = status_bar_h; } - LCD_FillByColor(x, 0, 240, clear_h, BLACK); + LCD_FillByColor(bat_x > 4 ? (uint16_t)(bat_x - 4) : 0, 0, 240, clear_h, BLACK); /* 鍦嗚澶栧3锛氬妗 + 鍐呮寲绌 */ - LCD_FillRoundRect(x, y, bat_w, bat_h, round_r, border_color); + LCD_FillRoundRect(bat_x, y, bat_w, bat_h, round_r, border_color); if(bat_w > 2 * stroke && bat_h > 2 * stroke) { - LCD_FillRoundRect(x + stroke, y + stroke, + LCD_FillRoundRect(bat_x + stroke, y + stroke, bat_w - 2 * stroke, bat_h - 2 * stroke, (round_r > stroke) ? (round_r - stroke) : 0, bg_color); @@ -1834,26 +1854,25 @@ void Draw_Battery_Icon(uint16_t x, uint16_t y, uint8_t battery_percent,uint8_t s inner_h = bat_h - 2 * fill_gap; fill_w = inner_w * battery_percent / 100; - /* 浠庡乏鍚戝彸瀹炲績濉厖锛屽搴︿笌鐧惧垎姣斾竴鑷 */ if(battery_percent > 0 && fill_w > 0) { if(fill_w > inner_w) { fill_w = inner_w; } - LCD_FillRoundRect(x + fill_gap, y + fill_gap, + LCD_FillRoundRect(bat_x + fill_gap, y + fill_gap, fill_w, inner_h, 1 * scale, fill_color); } - /* 鍙充晶姝f瀬灏忓嚫璧 */ - pole_x = x + bat_w; + pole_x = bat_x + bat_w; pole_y = y + (bat_h - pole_h) / 2; LCD_FillRoundRect(pole_x, pole_y, pole_w, pole_h, 1 * scale, border_color); - sprintf((char*)Info, "%d%%", battery_percent); - text_x = pole_x + pole_w + 2 * scale; + text_x = (uint16_t)(pole_x + pole_w + gap); text_y = (status_bar_h - text_size) / 2; + if ((int16_t)text_y < 0) + text_y = 0; LCD_ShowString(text_x, text_y, Info, WHITE, BLACK, text_size, 0); } diff --git a/tools/flash_app.bat b/tools/flash_app.bat index e096322..79971eb 100644 --- a/tools/flash_app.bat +++ b/tools/flash_app.bat @@ -1,7 +1,5 @@ @echo off -REM Flash YNGJ-GT1-M app via IAR cspybat (AT32 flash loader). -REM Do NOT pass Commander-style .jlink files to --jlink_script_file. - +REM Flash YNGJ-GT1-M app via IAR cspybat, then reset+run and wait for UI boot. setlocal set ROOT=%~dp0.. set OUT=%ROOT%\project\IAR_V7.4\YNGJ-GT1-M\Exe\YNGJ-GT1-M.out @@ -9,6 +7,7 @@ set GEN=%ROOT%\project\IAR_V7.4\settings\YNGJ-GT1-M.YNGJ-GT1-M.general.xcl set DRV=%ROOT%\project\IAR_V7.4\settings\YNGJ-GT1-M.YNGJ-GT1-M.driver.xcl set CSPY="C:\Program Files (x86)\IAR Systems\Embedded Workbench 7.3\common\bin\cspybat" set STAGE=C:\Temp\k1flash +set JLINK="C:\Program Files\SEGGER\JLink_V818\JLink.exe" if not exist "%OUT%" ( echo ERROR: missing %OUT% - build first @@ -18,8 +17,15 @@ if not exist "%OUT%" ( mkdir "%STAGE%" 2>nul copy /Y "%OUT%" "%STAGE%\YNGJ-GT1-M.out" >nul +echo [1/3] Downloading... %CSPY% -f "%GEN%" "--debug_file=%STAGE%\YNGJ-GT1-M.out" --download_only --backend -f "%DRV%" if errorlevel 1 exit /b 1 -"C:\Program Files\SEGGER\JLink_V818\JLink.exe" -CommandFile "%~dp0reset_run.jlink" -exit /b %ERRORLEVEL% +echo [2/3] Reset and run... +%JLINK% -CommandFile "%~dp0reset_run.jlink" +if errorlevel 1 exit /b 1 + +echo [3/3] Wait for auto PowerOn + logo (about 3s)... +timeout /t 3 /nobreak >nul +echo Done. UI should be on mode-select screen. +exit /b 0 diff --git a/tools/rtt_lcd_capture.py b/tools/rtt_lcd_capture.py index db4d339..c12271c 100644 --- a/tools/rtt_lcd_capture.py +++ b/tools/rtt_lcd_capture.py @@ -138,17 +138,26 @@ def capture_rtt_png(out_path: str, device: str, timeout_s: float, do_reset: bool buffer = b"" deadline = time.time() + timeout_s + header_off = -1 while time.time() < deadline: term = jlink.rtt_read(0, 1024) if term: print("RTT0:", bytes(term).decode("utf-8", errors="replace").strip()) - chunk = jlink.rtt_read(1, 8192) + chunk = jlink.rtt_read(1, 16384) if chunk: buffer += bytes(chunk) - if len(buffer) >= HEADER_SIZE and buffer[:4] == MAGIC: + # Drain stale bytes before SCRN (previous incomplete dumps). + header_off = buffer.find(MAGIC) + if header_off >= 0 and len(buffer) >= header_off + HEADER_SIZE: + if header_off > 0: + print(f"Discarded {header_off} stale RTT1 bytes before SCRN") + buffer = buffer[header_off:] break - time.sleep(0.01) + # Cap memory if SCRN never appears + if len(buffer) > 256 * 1024: + buffer = buffer[-65536:] + time.sleep(0.001) if len(buffer) < HEADER_SIZE or buffer[:4] != MAGIC: raise SystemExit("Timeout waiting for SCRN header on RTT channel 1")