设计师给了张横版 800×480 的欢迎图,产品屏幕却是竖着装的 480×800,LOGO 要在 U-Boot 阶段(内核还没起来)就显示。这篇记录从 PNG 到屏上点亮的完整管线,以及三个坑——其中"多放一张 BMP 就爆分区"这个,打包工具的报错信息几乎不会让你直接想到答案。

一、管线总览

1
2
3
4
5
6
源图(横版 800×480 PNG)
  → 缩放到 800×480
  → 逆时针旋转 90°(预旋转)
  → 480×800 竖版 24bpp BMP
  → 放到打包唯一认的路径
  → 打进 boot-resource 分区

核心就五行 Python:

1
2
3
4
img = Image.open(src).convert("RGB").resize((800, 480))
img = img.transpose(Image.ROTATE_90)   # 逆时针
img.save(dst, "BMP")                    # 480×800 24bpp
assert os.path.getsize(dst) == 1152054

二、三个确定性锚点

这种管线里最容易翻车的是"每一环都对个大概,合起来差 90°/差一个通道"。对策是给每环一个确定性锚点:

1. 尺寸公式当断言。 480×800×3 + 54(BMP 文件头)= 1152054 字节,一个字节都不能差。存成了 32bpp(每像素 4 字节)或调色板 BMP,文件大小立刻不对。转换脚本里直接 assert 文件大小,是最便宜的自校验。

2. 旋转方向要互补不要相同。 屏物理竖装、主控按横屏刷新,应用层(LVGL)配的是 ROTATION_270;那 LOGO 的预旋转就用 ROTATE_90(逆时针),正好补回来。方向推理一次不算数,上机看一眼;如果差 180° 或镜像,换 ROTATE_270 再来(脚本留个 --flip 选项就是为这个)。

3. 打包只认一个路径。 Tina 打包脚本只收 target/<芯片>/<板级>/configs/bootlogo.bmp,文件名、路径都不能变。放在别的位置的 bmp 不会进固件——“我放了怎么没效果"先查路径。

三、坑一:configs 目录里多了一张 BMP,分区爆了

换图时把旧 logo 备份成 bootlogo.old.bmp 留在同目录,打包直接失败:

1
ERROR: dl_file_size = 4588 sector / part_size = 2880 / update mbr fail

这个报错信息非常有误导性——看着像分区表配置坏了。真实原因:pack 会把 configs 目录下所有 *.bmp 全部收进 boot-resource 的 FAT 分区。两张 1.1MB 的图叠成 2.24MB,超过分区上限(2880 扇区 ≈ 1.4MB)。

规矩:configs 目录里永远只留一张 BMP,备份放目录外。

四、坑二:换图前先算体积账

boot-resource 分区 2880 扇区 ≈ 1.4MB,480×800×24bpp 恰好 1.1MB——余量只有 20%。以后想换更复杂的图(更高分辨率、双图切换),先算体积再动分区表;分区表一动,烧录升级的兼容性就是另一个故事了。

五、坑三:不信打包日志,信字节

打包日志说 success,不等于图真的在里面、且只在一处。最终验证做成字节级:把整包 img 当二进制,从 BMP 文件头起搜完整文件字节序列——

  • 恰好命中 1 次:图进去了,通过;
  • 命中 2 次:分区里混了旧图(就是坑一的场景);
  • 0 次:白打包了,别烧。

这类"打包工具静默吞内容/多收内容"的坑在嵌入式工具链里不止这一处,字节级验证是通用的最后防线。验证成本一分钟,烧一次板十分钟起步。

六、一条命令固化

整条管线最后收进 make_logo_from_image.py:源图进、bootlogo.bmp 出,自带尺寸断言和 --flip 选项。下次设计师再换图,一条命令转换 + 一次打包 + 一次字节验证,五分钟收工——把容易翻车的事变成不会翻车的流程,才是这类"小事"的正确收尾。