LVGL 屏幕颜色不对?先查 LV_COLOR_16_SWAP,别猜通道交换

写蓝显绿、写青显蓝、饱和度还低——看似「红绿蓝通道互换」,真相是 RGB565 字节序错位。一次印象深刻的误判复盘。

现象

ESP32-S3 + ILI9342C(320×240,4 线 SPI),LVGL 8 画的 UI:

  • 代码写 #5BA8E0(蓝)→ 屏幕显示淡绿
  • 代码写 #2EE6C8(青绿)→ 屏幕显示天蓝
  • 而且饱和度普遍偏低,颜色发灰

第一反应:面板 RGB 通道顺序不对(ILI 系列确实有 RGB/BGR 面板之分),于是写了个交换宏把绿蓝通道对调。

对了一半,换一组颜色就穿帮。

为什么通道交换解释不通

字节序错位会造成伪通道交换的假象:RGB565 一个像素占两个字节,SPI 线上的字节序和 LVGL 内存里不一致时,每像素两字节错位、R/G/B 的位被打散重组——看起来既像通道互换,又像掉饱和度。

穷举 6 种通道排列,每一种都能「部分解释」观察到的颜色,但拿 8 个观察点对拍,没有一种排列能全中。

真相

sdkconfig 里:

CONFIG_LV_COLOR_16_SWAP=y    # 正确(SPI 面板应如此)
CONFIG_LV_COLOR_16_SWAP=0    # 当时被静默改成了这个

LV_COLOR_16_SWAP=0 时,LVGL 存的 RGB565 字与 SPI 线上要求的字节序不匹配 → 全部颜色错位。改回 y,颜色立刻全对,根本不需要任何通道交换。

教训

  1. SPI 面板 + LVGL 8 颜色不对,第一条命令查 sdkconfig 里的 LV_COLOR_16_SWAP(sdkconfig.old 能看出它有没有被改过),再谈通道交换
  2. 判断「屏幕变换是不是恒等」要用多种色相交叉验证(红/绿/蓝/灰各来一个),全中才敢下结论;单一颜色对上就开改,大概率是在拟合错误模型
  3. 交换宏别删,保持恒等(#define UI_SWAP_GB(h) (h))——万一以后真换到 BGR 面板,改一处就行
  4. 把 CONFIG_LV_COLOR_16_SWAP=y 钉进 sdkconfig.defaults,防止它被静默改回去