From 6f19486b1697b14788ee733796a161e2e494f507 Mon Sep 17 00:00:00 2001 From: yuquanjun Date: Sat, 26 Sep 2026 13:11:17 +0800 Subject: [PATCH] fix(boot): show the burn-mode title in white The source picture painted the glyphs in the page background color, so the screen stayed black. Draw those strokes in white when the external image has no light pixels. Co-authored-by: Cursor --- .../project/src/boot_flash_mode_ink.h | 27 +++++++++++ AT32F403ARCT7_BOOT/project/src/main.c | 43 ++++++++++++++++-- .../09_烧录模式/烧录模式-240x320.png | Bin 2595 -> 3006 bytes tools/gen_ui0902_assets.py | 35 ++++++++++++++ 4 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 AT32F403ARCT7_BOOT/project/src/boot_flash_mode_ink.h diff --git a/AT32F403ARCT7_BOOT/project/src/boot_flash_mode_ink.h b/AT32F403ARCT7_BOOT/project/src/boot_flash_mode_ink.h new file mode 100644 index 0000000..63681ba --- /dev/null +++ b/AT32F403ARCT7_BOOT/project/src/boot_flash_mode_ink.h @@ -0,0 +1,27 @@ +#ifndef BOOT_FLASH_MODE_INK_H +#define BOOT_FLASH_MODE_INK_H +#include + +/* 烧录模式.png 的白字笔画。原图把字画成页面底色,铺到黑底上就是黑屏。 */ +#define BOOT_FLASH_INK_X 78 +#define BOOT_FLASH_INK_Y 149 +#define BOOT_FLASH_INK_W 86 +#define BOOT_FLASH_INK_H 21 +static const uint8_t boot_flash_ink[231] = { + 0x1C,0x30,0x00,0x00,0x00,0x01,0x83,0x18,0x00,0x0E,0x40,0x1C,0x30,0x00,0xFF,0xFE, + 0x01,0x83,0x18,0x00,0x0E,0xE0,0x1C,0x3F,0xF0,0xFF,0xFE,0x01,0xBF,0xFF,0x00,0x0E, + 0x70,0x1D,0xFF,0xE0,0x00,0x06,0x01,0xBF,0xFF,0x00,0x0E,0x30,0xDF,0xFC,0x60,0x00, + 0x06,0x0F,0xE3,0x18,0x3F,0xFF,0xF8,0x7E,0x1C,0xE0,0x7F,0xFE,0x0F,0xE0,0x00,0x3F, + 0xFF,0xF8,0x7C,0x0F,0xC0,0x7F,0xFE,0x03,0x9F,0xFE,0x00,0x06,0x00,0x7C,0x0F,0x10, + 0x00,0x06,0x03,0x9C,0x0E,0x00,0x06,0x00,0x7C,0xFF,0x31,0xFF,0xFF,0xC3,0x9F,0xFE, + 0x00,0x06,0x00,0x7C,0xF3,0xF3,0xFF,0xFF,0xC7,0xDF,0xFE,0x3F,0xF6,0x00,0x1C,0x81, + 0xE0,0x41,0xC1,0x07,0xF8,0x06,0x3F,0xF6,0x00,0x1C,0x00,0x40,0xE1,0xC3,0x0F,0xFF, + 0xFE,0x03,0x86,0x00,0x1D,0xFF,0xF0,0x71,0xE7,0x8F,0x9F,0xFE,0x03,0x07,0x00,0x1F, + 0xFF,0xF0,0x3B,0xFE,0x0D,0x80,0xC0,0x03,0x07,0x00,0x1E,0x33,0x00,0x1F,0xFC,0x09, + 0xBF,0xFF,0x03,0x03,0x18,0x3F,0x33,0x10,0x7F,0xFC,0x01,0xBF,0xFF,0x03,0x03,0x18, + 0x32,0x73,0x11,0xF9,0xCF,0x01,0x81,0xE0,0x07,0xFB,0x98,0x70,0x73,0x13,0xE1,0xC7, + 0xC1,0x87,0xF8,0x3F,0xF9,0xD8,0x61,0xE3,0xF1,0x8F,0xC1,0xC1,0x9F,0x3F,0x3F,0x01, + 0xF8,0x61,0xC1,0xF0,0x0F,0x80,0x01,0xBC,0x0F,0x00,0x00,0xF0,0x00,0x00,0x00,0x0F, + 0x00,0x01,0xB0,0x02,0x00,0x00,0x20, +}; +#endif diff --git a/AT32F403ARCT7_BOOT/project/src/main.c b/AT32F403ARCT7_BOOT/project/src/main.c index 2ad1713..833e95b 100644 --- a/AT32F403ARCT7_BOOT/project/src/main.c +++ b/AT32F403ARCT7_BOOT/project/src/main.c @@ -38,6 +38,7 @@ #include "Drv_TM1617_RGB.h" #include "UI0902_Res_Addr.h" #include "drv_nvm.h" +#include "boot_flash_mode_ink.h" /* private includes ----------------------------------------------------------*/ /* add user code begin private includes */ @@ -111,6 +112,40 @@ static uint8_t Boot_NvmUsbUpdateRequested(void) return (nvm->data.param.UsbMode == NVM_USB_UPDATE) ? 1 : 0; } +/* 外部图把字画成了页面底色,铺出来是黑屏。字行中间有接近白色的像素才采用它。 */ +static uint8_t Boot_FlashModeHasLight(void) +{ + uint8_t row[172]; + uint16_t i; + W25Q128_Read(row, + UI0902_FLASH_MODE_ADDR + (158ul * 240ul + 78ul) * 2ul, + (uint16_t)sizeof(row)); + for (i = 0; i + 1u < sizeof(row); i += 2) + { + uint16_t c = (uint16_t)(((uint16_t)row[i] << 8) | row[i + 1]); + if (c >= 0xC618) + return 1; + } + return 0; +} + +static void Boot_DrawFlashModeInk(void) +{ + uint16_t row, col, stride; + LCD_FillByColor(0, 0, 240, 320, 0x0042); + stride = (uint16_t)((BOOT_FLASH_INK_W + 7u) >> 3); + for (row = 0; row < BOOT_FLASH_INK_H; row++) + { + const uint8_t *p = boot_flash_ink + (uint32_t)row * stride; + for (col = 0; col < BOOT_FLASH_INK_W; col++) + { + if (p[col >> 3] & (uint8_t)(0x80u >> (col & 7))) + LCD_DrawPoint((uint16_t)(BOOT_FLASH_INK_X + col), + (uint16_t)(BOOT_FLASH_INK_Y + row), WHITE); + } + } +} + static void Boot_NvmClearUsbUpdate(void) { NvmData_Type tmp; @@ -211,17 +246,15 @@ int main(void) { uint8_t peek[4]; W25Q128_Read(peek, UI0902_FLASH_MODE_ADDR, 4); - if (!(peek[0] == 0xFF && peek[1] == 0xFF && peek[2] == 0xFF && peek[3] == 0xFF)) + if (!(peek[0] == 0xFF && peek[1] == 0xFF && peek[2] == 0xFF && peek[3] == 0xFF) && + Boot_FlashModeHasLight()) { LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_FLASH_MODE_W, UI0902_FLASH_MODE_H, UI0902_FLASH_MODE_ADDR); } else { - LCD_FillByColor(0, 0, 240, 320, BLACK); - LCD_ShowChinese_AutoAlign(0, 240, 150, - (uint8_t *)"\xC9\xD5\xC2\xBC\xC4\xA3\xCA\xBD\x00", - LCD_ALIGN_CENTER, WHITE, BLACK, 0, 24); + Boot_DrawFlashModeInk(); } } /* 画面出来后再清标志,避免还没进烧录就被下一次复位跳回 App。 diff --git a/tools/assets_0902/09_烧录模式/烧录模式-240x320.png b/tools/assets_0902/09_烧录模式/烧录模式-240x320.png index f2f91da29f3aedee1c95b3a4b7bf31820e41aad6..5dbf6315f00f2987d5d6ce9360cdeca0ef91426c 100644 GIT binary patch literal 3006 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 Fe*= 40 and (r + g + b) > 400: + light += 1 + if light > 50: + return rgba + out = Image.new("RGBA", (w, h), PAGE_BG + (255,)) + opx = out.load() + for y in range(h): + for x in range(w): + r, g, b, a = px[x, y] + if a < 8: + continue + opx[x, y] = ( + (255 * a + PAGE_BG[0] * (255 - a)) // 255, + (255 * a + PAGE_BG[1] * (255 - a)) // 255, + (255 * a + PAGE_BG[2] * (255 - a)) // 255, + 255, + ) + return out + + def rgba_to_rgb565_opaque(im): """Full-screen boot/charge/flash: keep dark bg; flatten RGBA onto black (not white). @@ -299,6 +332,8 @@ def main(): entries = {} for name, rel in EXTERNAL: im = Image.open(SRC / rel) + if name == "FLASH_MODE": + im = flash_mode_on_page(im) if name in ("ROW_UNIVERSAL_NOT", "ROW_UNIVERSAL_SEL", "ROW_NORMAL_NOT", "ROW_NORMAL_SEL", "ROW_EXPERT_NOT", "ROW_EXPERT_SEL"): im = im.resize(ROW_RESIZE, Image.LANCZOS) data, w, h = rgba_to_rgb565(im)