如果一张图片是1MB【对应的数组已存在spi flash里】,ram为64KB的单片机能将其显示在屏幕上吗?不考虑流畅度之类的。大概的一个操作或流程是怎么样的?
离线
逐块刷新,从spi flash里读一小块数据到RAM然后刷新屏幕
离线
移植文件系统接口lv_port_fs_template.c,用imageconverter把图片转为bin文件存入文件系统,需要用到图片的地方填入图片文件的路径就行了。比如lv_obj_set_style_bg_img_src(homepage, "F:/bg.bin", 0);
离线
double33 wrote:
逐块刷新,从spi flash里读一小块数据到RAM然后刷新屏幕
怎么与lv_image_set_src()关联起来?就是用lvgl的api进行操作
离线
分块缓冲就是分配一小块ram,每次读一块,然后每次写屏更新指定块的偏移坐标。
lvgl有全屏缓冲和分块缓冲,现在有AI了,直接让AI帮你写一个分块缓冲的lvgl demo。
离线
Icing wrote:
移植文件系统接口lv_port_fs_template.c,用imageconverter把图片转为bin文件存入文件系统,需要用到图片的地方填入图片文件的路径就行了。比如lv_obj_set_style_bg_img_src(homepage, "F:/bg.bin", 0);
需要修改lv-port-fs里的读写
离线
@与非门
既然用到了文件路径,就要有文件系统。
lvgl的虚拟文件系统非常简单,只是要把fs_open、fs_close、fs_read这样的函数与真实文件系统的函数对应上。
对于spiflash的文件系统,我习惯用littlefs或romfs
离线
Icing wrote:
@与非门
既然用到了文件路径,就要有文件系统。
lvgl的虚拟文件系统非常简单,只是要把fs_open、fs_close、fs_read这样的函数与真实文件系统的函数对应上。
对于spiflash的文件系统,我习惯用littlefs或romfs
spi_flash与fs对接参考这个工程{an-lvgl_demo_for_small_mcu-masterx}。
目前在找TF卡/SD卡与fs相对接的。
离线
Icing wrote:
@与非门
既然用到了文件路径,就要有文件系统。
lvgl的虚拟文件系统非常简单,只是要把fs_open、fs_close、fs_read这样的函数与真实文件系统的函数对应上。
对于spiflash的文件系统,我习惯用littlefs或romfs
littlefs/romfs,这两种的话更新图片bin文件是不是有什么格式要求?目前是采用直接读w25q64的操作。
离线
Icing wrote:
移植文件系统接口lv_port_fs_template.c,用imageconverter把图片转为bin文件存入文件系统,需要用到图片的地方填入图片文件的路径就行了。比如lv_obj_set_style_bg_img_src(homepage, "F:/bg.bin", 0);
lvgl RGB565是不是支持透明?在一个容器里放了一些控件,当容器透明度设置为0,容器里的控件就都消失了
离线
考虑一下C23新标准,可直接嵌入二进制文件,连编译都省了
离线
M3pao 说:
考虑一下C23新标准,可直接嵌入二进制文件,连编译都省了
这要编译器支持吧(另外这个应该没能解决帖子所提的问题吧)
离线
@与非门 你可以点开这个网站看一下 https://lvgl.io/tools/imageconverter ,图片转为bin文件的方法如图所示:
离线
Icing 说:
@与非门 你可以点开这个网站看一下 https://lvgl.io/tools/imageconverter ,图片转为bin文件的方法如图所示:/files/members/16482/screenshot-20260513-092301.png
生成bin文件采用的是lvimgtool。
离线
这个问题我感觉可以分成两层看:一层是“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 图片显示流程都能先验证起来。
离线
这个我补充一个比较落地的做法:如果你的图片已经是 lvimgtool 生成的 bin,其实不用先把 1MB 全部搬进 RAM,关键是把“外部 flash 的随机读”包装成 LVGL 能读的文件接口。
我以前处理这种小 RAM 场景,一般会先做一个很土但是好用的只读资源表,不一定一上来就搞 fatfs/littlefs:
typedef struct {
const char *name;
uint32_t addr;
uint32_t size;
} res_item_t;
static const res_item_t res_table[] = {
{"bg.bin", 0x00100000, 1024 * 1024},
};然后 LVGL 的 fs_open/fs_read/fs_seek 里面根据文件名找到 flash 地址,read 的时候就是:
w25qxx_read(handle->base + handle->pos, buf, btr);
handle->pos += btr;这样上层还是:
lv_image_set_src(img, "F:/bg.bin");但底层根本不需要真正的 FAT 文件系统。对 W25Q64 这种固定资源显示来说,这个方案反而简单、快、坑少。
64KB RAM 能不能显示 1MB 图片?能,但要注意两件事:
LVGL 的 draw buffer 不要开全屏,开几行就行,比如 5 行、10 行。
图片格式最好别用需要大块临时解码缓存的格式。bin/raw RGB565 最省事,代价就是 flash 占用大一点。
还有一个容易踩的点:如果图片在 flash 里不是 lvgl image bin,而是你自己裸 RGB565 数组,那 lv_image_set_src() 不会自动知道宽高和格式。要么你自己补 LVGL 图片头,要么自己写 decoder,要么就绕开 lv_image,自己按行读出来后直接 blit 到屏幕区域。
所以我建议先不要纠结文件系统,先把路径读通:F:/bg.bin -> fs_open -> 找 offset -> fs_read -> w25qxx_read。
这个闭环跑通以后,再考虑换 littlefs/fatfs,就很清楚问题在哪一层了。
离线