这个问题我感觉可以分成两层看:一层是“LVGL 怎么认这个图片”,另一层是“64KB RAM 怎么把 1MB 图片刷出来”。
先说结论:64KB RAM 是可以显示外部 Flash 里的大图的,但前提是不要把整张图读进 RAM,而是让 LVGL/你的驱动按需读一小段,或者自己按行/按块刷屏。
如果你现在已经用 lvimgtool 生成了 bin,我建议优先走 LVGL 的 image decoder / fs 这条路,而不是把它当成普通 C 数组去 lv_image_set_src()。
大概流程是这样:
图片用 lvimgtool 转成 LVGL 能识别的 bin
这个 bin 前面会带 LVGL 图片头,后面才是像素数据。也就是说它不是随便一段 RGB565 裸数据,LVGL 读取时会先读 header,知道宽高、颜色格式、是否有 alpha。
外部 Flash 上做一个“最小文件接口”
不一定非要上 fatfs/littlefs。你如果现在就是直接读 W25Q64,也可以自己做个很薄的只读文件系统,比如:
文件名 bg.bin 对应 flash offset 0x100000
文件长度写死或放一个表
fs_open() 根据名字找到 offset
fs_read() 就从 offset + pos 读数据
fs_seek() 改当前位置
这样 LVGL 以为自己在读文件,其实底层就是 w25qxx_read(addr, buf, len)。
接到 LVGL 的 fs 接口
也就是改 lv_port_fs_template.c 里这些函数:
open
close
read
seek
tell
然后路径可以类似:
lv_image_set_src(img, "F:/bg.bin"); 这里的 F: 只是 LVGL 里注册的盘符,不代表真的要有 FAT 文件系统。
RAM 小的问题
LVGL 不应该整张 1MB 读进来,它会通过 decoder/fs 分段读取。真正要注意的是你的 draw buffer 不要开太大,比如开几行高度就行:
```c
static lv_color_t buf[HOR_RES * 10];
```
这种 10 行缓冲比全屏缓冲省很多 RAM。
透明问题
RGB565 本身没有 alpha 通道,所以“RGB565 支不支持透明”要看你图片格式是不是带 alpha,或者是否用了 chroma key。普通 RGB565 bin 是没有每像素透明度的。
另外你说“容器透明度设置为 0,里面控件也消失”,这个是正常的。对象整体 opacity 会影响子对象一起透明。如果只是想容器背景透明,应该改背景透明度,不要把整个 object 的 opacity 设 0,例如:
lv_obj_set_style_bg_opa(cont, LV_OPA_TRANSP, 0); 而不是把 opa 整体设成 0。
我个人建议你现在别先纠结 fatfs/littlefs。你用 W25Q64 直接读的话,先做一个只读版 fs 最快:文件名 -> flash 偏移 -> read/seek。等这个跑通了,再决定要不要换 littlefs/fatfs。这样路径接口、LVGL 图片显示流程都能先验证起来。
RP2040 可以驱动 OV7670(不带 FIFO),但关键不是 SCCB/I2C 配寄存器,而是图像数据采集必须用 PIO + DMA 来做,单靠 CPU 轮询基本扛不住。
OV7670 不带 FIFO 时,数据流大概是:
XCLK:由 RP2040 输出给摄像头,一般 8~12MHz 起步,太高会把采集压力拉满;
PCLK:摄像头输出,每个 PCLK 对应 D0~D7 一次有效数据;
VSYNC:帧同步;
HREF:行有效;
D0~D7:8 位并口数据。
推荐实现思路:
用 PWM/PIO 给 OV7670 提供 XCLK。
先不要追求 30fps,建议把 XCLK 降到 8MHz 左右,先保证能稳定采一帧。
用 I2C/SCCB 初始化 OV7670。
先配置成低分辨率,例如 QQVGA 160x120,格式用 RGB565 或 YUV422。RP2040 RAM 只有 264KB,完整 VGA RGB565 放不下:640x480x2 约 600KB,所以必须降分辨率或边采边处理。
用 PIO 采 D0~D7。
PIO 程序等待 PCLK 边沿,在 HREF 有效期间把 8bit 数据 push 到 RX FIFO;再用 DMA 从 PIO RX FIFO 搬到 RAM。这样 CPU 只负责帧/行状态和后处理。
VSYNC/HREF 可以用 GPIO 中断或 PIO 等待处理。
简单做法是:VSYNC 到来时开始一帧;每行 HREF 有效时启动 DMA 收这一行;HREF 结束停止/切换下一行缓冲。
内存上建议先做单行/双行缓冲。
如果只是显示到 LCD,可以一边采一边刷屏;如果要存整帧,QQVGA RGB565 是 1601202=38400 字节,RP2040 可以承受。QVGA 3202402=153600 字节也勉强可以,但余量会小很多。
调试顺序建议:
先只验证 SCCB,读写寄存器确认摄像头有 ACK;
再输出 XCLK,用示波器/逻辑分析仪看 PCLK、VSYNC、HREF 是否正常;
再用 PIO 采一行固定长度数据;
最后再拼成整帧。
如果用 C SDK,可以参考 RP2040 官方 pico-examples 里的 PIO + DMA 例子,再把 PIO 输入逻辑改成按 PCLK 采 8 位并口。网上很多 MicroPython 例程能跑,核心也是一样:寄存器初始化 + PIO/DMA 采样,只是 C 里要自己把 PIO 和 DMA 部分搭起来。
不建议一开始就上 VGA。先用 QQVGA/RGB565 或 YUV422 跑通一帧,确认颜色/行同步没错,再逐步提高分辨率和时钟。
点击下载之后马上超时,通常不像是分区启动问题,更像是 ymodem 传输还没真正开始,接收端没有收到有效数据或握手没对上。
可以优先查这几项:
串口波特率、数据位、校验位、流控是否和 ymodem_ota 工具一致,尤其确认没有开硬件流控;
点击下载后设备端是否持续发送 C 字符等待 YMODEM,如果没有,说明 OTA 接收流程可能没进入;
PC 端工具是否选择了 YMODEM,而不是 XMODEM/ZMODEM,文件名和文件大小是否正常发出;
升级包大小是否超过目标分区,os/os_r 能启动不代表 OTA 写入边界一定正确;
打开 OTA 模块日志,重点看超时发生在握手阶段、接收头包阶段,还是写 flash 阶段;
如果串口同时输出 log,可能会干扰 ymodem 数据流,最好确认下载串口和日志串口是否分开,或临时降低/关闭日志。
我会先抓串口看有没有 C 握手字符。如果连头包都没收到,就先查串口/工具/流控;如果收到后写失败,再查分区表和 flash 写入。
这种老安卓平板不建议直接随便刷“同 CPU”的包,A220/Softwinner EVB 只能说明平台相近,真正能不能刷还要看屏、触摸、WiFi、PMIC、分区表这些是否一致。刷错后很容易黑屏、触摸不可用,甚至需要短接/量产工具救砖。
建议先按这个顺序处理:
先备份原机固件,至少把分区表、boot、system、recovery 备出来;
进设置或 adb 看 ro.product.*、ro.build.fingerprint、屏幕分辨率、触摸芯片型号;
如果还能开 adb,可以先尝试清数据/恢复出厂,或者替换/修复应用管理相关 apk;
真要刷机,优先找完全同型号主板/同触摸/同屏参的固件,不要只按 A220 搜;
全志平台通常还要准备 PhoenixSuit/LiveSuit 之类工具和对应 img,刷前确认能进 FEL/烧录模式。
如果只是想做学习机,能进系统的话,也可以先尝试 adb 安装第三方桌面/文件管理/应用市场,未必一定要整包刷机。
SSC338Q 这类 SigmaStar SDK 通常不是公开下载型资源,更多是走方案商、代理或板卡厂家渠道。公开论坛里即使能找到,也经常是旧版或不完整包。
建议先确认几个信息再找:
芯片完整丝印/封装,是 SSC338Q 还是同系列马甲型号;
板子使用的 DDR、Flash、sensor 型号,不同配置的 BSP 不能直接混用;
你要验证的是应用层程序、驱动,还是 MPP/编码/ISP 相关功能;
如果只是编译用户态 demo,看看原固件里是否已有交叉工具链、头文件或 sample;
如果要改内核、uboot、sensor、ISP,就需要完整 BSP/SDK,最好找卖板子的渠道要。
简单说:应用层验证可以先找工具链和头文件;涉及媒体库/驱动/启动链路,就别只找零散 sample,直接要完整 SDK 更稳。
SSC338Q 这类 SigmaStar 平台的 SDK 一般公开渠道比较少,通常要从模组/板卡供应商或方案商那里拿,对应到具体芯片、DDR、sensor、板级配置后才比较好用。
如果只是想先验证能不能编译一点东西,可以先确认几个信息:
手上的板子具体型号、DDR 容量、Flash 类型(SPI NAND/eMMC 等);
需要的是 Linux SDK、IPC SDK,还是只要交叉编译工具链和头文件;
是否已经有可启动固件,能否从系统里看 /proc/cpuinfo、内核版本、busybox 环境;
如果目标只是跑用户态程序,很多时候先拿到对应 arm 交叉编译链就能做初步验证,不一定马上需要完整 SDK。
完整 SDK 最稳还是找卖板子的厂家要,顺便让对方给一份板级配置和编译说明,否则拿到别的板子的包也可能卡在 uboot、kernel dts 或 sensor 配置上。
Rockchip 的 Android SDK 一般不会在公开页面直接放完整源码包,redmine 上有些链接只给 update.img 或固件包,看起来就会像“下载到了但不是 SDK”。
可以从这几个方向确认一下:
先看下载目录里有没有 .repo、manifest.xml、build.sh、device/rockchip/、u-boot/、kernel/ 这些目录/文件;如果只有一个 update.img,那基本就是量产固件,不是源码 SDK;
RK3326 属于比较老的平台,完整 Android SDK 通常需要找板卡厂家、方案商或 Rockchip 授权账号获取;
如果只是做内核/驱动适配,可以先找对应板子的 kernel、u-boot、device tree,不一定非要完整 Android SDK;
也可以问清楚板子型号和 Android 版本,比如 Android 8/9/10,不同版本的 SDK 包差异挺大。
建议把你下载到的文件名或目录结构贴一下,大家更容易判断是下错入口、权限不够,还是本来就只开放了固件包。
这个资料挺有用,A33/R16 的板子现在很多链接都容易失效,能把原理图和 dts 一起留一份很方便后面查。
补充一点:BPI M2M 这类板子如果拿来做主线内核适配,可以重点对照这几块:
PMIC/电源树,尤其 AXP223 的 DCDC/LDO 分配;
DRAM 配置,A33/R16 不同板子的 DDR 参数可能不通用;
WiFi/BT 模块的 SDIO、enable GPIO、32k 时钟;
LCD、CSI、音频这些复用脚,最好以原理图为准再核 dts;
如果用的是 sun8i-r16-bananapi-m2m.dts,移植到 A33 其他板时不要直接照搬 regulator 和 pinctrl。
这类帖子建议长期保留,后面有人找 A33/R16 原理图会省很多时间。
移植步骤整体方向是对的,不过 i.MX6UL 新增板级支持时,除了文件名/TARGET 对齐,还建议重点核对 SPL、imximage 和 pinmux 这几处,否则很容易“能编译但不能启动”。
可以按这个清单再过一遍:
CONFIG_TARGET_...、defconfig 文件名、SYS_BOARD、SYS_CONFIG_NAME、board 目录名必须完全一致;
imximage.cfg 里的 DCD/PLUGIN 是否适配你自己的 DDR、电源和启动介质,不能只复制 EVK;
如果走 eMMC,确认 USDHC 的 iomux、pad 配置、供电、reset 没沿用 EVK 不匹配的管脚;
arch/arm/dts/Makefile 加了 dtb 后,确认最终编译产物里确实生成并打包了对应 dtb;
SPL 阶段如果启用,board_init_f、DDR init、clock init、watchdog 这些也要跟板子匹配;
findfdt 只影响运行时选择 dtb,不等于启动镜像里一定带了这个 dtb,最好用 dumpimage 或编译输出确认。
如果现在已经能进 U-Boot prompt,主要查 env/fdt/emmc;如果连 SPL/U-Boot 都没打印,优先查 imximage.cfg、DDR 初始化和启动介质管脚。
从这段 log 看,CPU2/CPU3 被 shutdown 后又 booted secondary processor,比较像系统的 hotplug/cpufreq/cpu budget 策略在动态开关核心,不一定是异常崩溃。
全志老 BSP 里经常有类似 CPU Budget、hotplug、thermal 相关策略:负载低或场景切换时会关掉部分核心,负载上来再拉起。你这里前面也有:CPU Budget:update CPU 0 cpufreq max...
后面紧跟 cpu hotplug 日志,所以优先怀疑是 cpufreq/cpubudget 在工作。
可以这样确认:
看 /sys/devices/system/cpu/cpu*/online,观察核心是否会随负载变化;
跑个 stress 或死循环把负载拉高,看 CPU2/CPU3 是否会重新 online;
检查内核配置/启动脚本里是否启用了 CONFIG_CPU_HOTPLUG、sunxi cpu budget、thermal 相关服务;
如果想临时固定多核,可以尝试手动 echo 1 > /sys/devices/system/cpu/cpu2/online,并停掉相关 hotplug/cpubudget 服务。
如果没有 panic/oops,也没有业务异常,只看到 shutdown/booted secondary processor,通常不是“核心坏了”,而是电源/温控/负载策略在动态关核。
这个思路挺适合价签这类小屏设备的,浏览器上传图片后直接刷屏,调试和使用都方便。
上传后显示慢几秒,除了 2.4G WiFi 本身慢,也可以从这几个方向优化一下:
前端上传前先把图片缩放到屏幕实际分辨率,再转 jpg/png,避免传大图到板端再处理;
板端收到图片后尽量直接写 framebuffer 或显示缓存,减少中间格式转换;
如果屏幕是黑白/灰阶墨水屏,可以在浏览器端先做抖动/灰度转换,只上传最终位图;
HTTP server 里上传缓存不要太小,分块写文件时避免频繁 fsync;
可以加一个 /status 接口,上传后浏览器轮询显示“接收中/转换中/刷新中”,体验会好很多。
如果后面要做成常用工具,建议把图片预处理尽量放到浏览器端,F1C100S 这边只负责接收和刷屏,速度会明显好一些。
U-Boot 2018.07 本身不是完全不能做 DSI,但全志平台上能不能亮,主要看你这份 BSP 的 U-Boot 显示驱动链路有没有把 DSI 部分移植完整。
只把内核 dts 的 lcd 节点复制到 U-Boot 通常不够,建议重点查:
U-Boot 阶段是否真的调用到了 lcd/panel 的 init 函数,可以先加打印确认;
DSI host、TCON、clock/reset、GPIO、power regulator、panel init command 这些是否都在 U-Boot 里初始化了;
背光常亮只能说明背光 GPIO/电源开了,不代表 DSI 已经出图;
内核能亮,说明硬件和屏参大概率没问题,可以对照内核启动日志,把 DSI 初始化顺序、lane 数、format、timing、panel init code 搬到 U-Boot 侧;
如果 U-Boot 里只有 RGB/LVDS 路径,没有 DSI host 驱动,那 menuconfig 选中 panel 也不会亮。
我建议先在 U-Boot 的 display init 入口、panel probe/init、dsi enable 这些位置加 log,确认卡在哪一层。
这个一般不是 SDK 本身编译不过,而是 Eclipse 工作区/工程的文本编码和源码实际编码不一致。
可以先试这几步:
Eclipse 里 Window -> Preferences -> General -> Workspace,把 Text file encoding 改成 UTF-8;
右键工程 Properties -> Resource,确认 Text file encoding 也是 UTF-8;
如果是导入旧 SDK,里面有些中文注释文件可能是 GBK/GB2312,可以单独把报错文件转成 UTF-8,或者在工程属性里临时设成 GBK 看是否消失;
也检查一下路径里有没有中文或特殊字符,老版本 Eclipse/CDT 有时也会受影响。
如果方便的话,把具体报错行贴出来更容易判断,是“文件编码无法解析”,还是编译器参数里 charset 不匹配。
USB HS 下 Bulk 端点的 wMaxPacketSize 按规范确实必须是 512,不是 128/256/512 可选。
FS Bulk 才允许 8/16/32/64;HS Bulk 是固定 512。
所以 WinUSB 这里不是因为 MS OS 2.0 特殊,而是配置描述符里 HS Bulk endpoint 的 wMaxPacketSize=128/256 本身就是不合规的。Windows 在拿到配置描述符后停止继续枚举,反复重试几次,这个现象也符合“描述符校验失败/配置不可用”的表现。
之前 U 盘例程里 wMaxPacketSize=128 还能工作,建议确认几件事:
当时设备是否真的跑在 High-Speed,而不是 Full-Speed;
抓包看到的 endpoint descriptor 是不是当前实际使用的 HS config;
是否存在 Device Qualifier / Other-Speed Configuration 描述符混淆;
Windows 的 Mass Storage 栈可能容忍了某些不规范描述符,但这不代表规范允许。
结论:HS Bulk endpoint 建议老老实实填 512。WinUSB 下更应该按规范来,否则 Windows 很可能直接拒绝配置。