1、课程导论:为什么需要外部存储加载图片?DMA2D在LVGL中的角色
各位同学好,我是你们这趟LVGL实战课的老朋友。今天咱们开篇就聊一个很现实的问题:为什么非要用外部存储来加载图片?DMA2D又是个什么角色?
说实话,我刚开始用LVGL做嵌入式UI时,也踩过不少坑。那时候觉得,把图片直接编译进固件里多省事,一个数组搞定一切。结果呢?项目做到一半,客户要求加几张高清背景图,Flash直接爆了。嗯,从那以后我就再也不敢小看外部存储了。
1.1 内部Flash的“天花板”
先看一组数据,你就明白了。
| 存储介质 | 典型容量 | 典型读取速度 | 成本(每MB) |
|---|---|---|---|
| MCU内部Flash | 512KB ~ 2MB | ~30MB/s | 高 |
| 外部SPI Flash | 8MB ~ 64MB | ~10MB/s | 低 |
| 外部SD卡 | 2GB ~ 32GB | ~4MB/s | 极低 |
你看,内部Flash容量小、成本高。一张800×480的RGB565图片,裸数据就要768KB。你想想看,MCU内部Flash总共才1MB,放两张图就满了,代码往哪搁?
我个人习惯是:所有UI资源图片全部放在外部存储,内部Flash只放启动代码和关键数据。这样项目后期加图、换图,改个文件系统路径就行,不用重新烧录固件。
1.2 外部存储带来的新问题
但外部存储也不是完美的。它带来了三个新麻烦:
- 读取速度慢:SPI Flash的读取速度远低于内部Flash,直接读出来显示,画面会卡顿。
- 格式不统一:外部存储里存的是JPEG、PNG这类压缩格式,LVGL不能直接显示,得先解码。
- 内存压力大:解码后的原始位图数据量巨大,MCU的RAM根本扛不住。
举个例子。我在一个智能家居面板项目里,用了800×480的屏幕,显示一张JPEG背景图。如果不做任何优化,直接解码到RAM,需要768KB的缓冲区。而那颗STM32H743的RAM总共才1MB,还要跑系统、跑LVGL、跑应用逻辑……结果就是内存溢出,系统反复重启。
1.3 DMA2D来救场
那DMA2D是干嘛的?说白了,它就是个硬件加速的图形搬运工。
DMA2D(也叫Chrom-ART)是STM32系列MCU里的一个专用图形DMA控制器。它能在不占用CPU的情况下,完成以下操作:
- 内存拷贝:把数据从A地址搬到B地址
- 色彩格式转换:比如把ARGB8888转成RGB565
- 图像混合:两张图叠加,带透明度
- 填充:用固定颜色填充一块区域
你想想看,如果没有DMA2D,CPU得亲自一条一条像素地处理。一张800×480的图,384000个像素,每个像素做一次格式转换,CPU就啥也别干了。而DMA2D可以在后台默默完成,CPU继续跑你的业务逻辑。
1.4 本章知识体系
为了让你对整个课程有个全局认识,我画了一张结构图。它展示了外部存储、DMA2D、LVGL三者之间的关系。
1.5 课程要解决的核心问题
整个课程围绕三个核心问题展开:
- 怎么从外部存储读取图片?——文件系统怎么挂载?路径怎么配置?LVGL的文件系统接口怎么对接?
- 怎么用DMA2D做色彩转换?——外部存储里存的可能是JPEG,解码后是ARGB8888,但屏幕需要RGB565。DMA2D怎么配置才能高效转换?
- 显示参数怎么配置?——LTDC的时序、层参数、帧缓冲地址,这些参数怎么和DMA2D配合?