硬件接口基础:SPI、SDIO、QSPI等常见外部存储接口对比与选型
做嵌入式UI,特别是用LVGL加载外部存储图片时,选对接口比选对芯片还重要。我见过不少项目,代码写得漂亮,UI设计也出彩,结果卡在图片加载速度上——说白了,就是接口没选对。
这一章,咱们把SPI、SDIO、QSPI这几个常见接口掰开揉碎聊清楚。不扯理论,只讲实战。
接口速览:一张表说清差异
先给个总览。我习惯把接口选型比作「选交通工具」——SPI是自行车,SDIO是汽车,QSPI是高铁。各有各的适用场景。
| 接口 | 数据线数 | 典型时钟 | 理论峰值 | 硬件复杂度 | 典型场景 |
|---|---|---|---|---|---|
| SPI | 1条数据线(MISO/MOSI) | 20-50 MHz | ~50 Mbps | 低(4线) | 小容量Flash、低分辨率图片 |
| Dual/Quad SPI | 2/4条数据线 | 20-50 MHz | ~200 Mbps | 中(6线) | 中等容量、中等分辨率图片 |
| QSPI | 4条数据线(全双工) | 80-120 MHz | ~480 Mbps | 中高(6线+) | 大容量、高分辨率、频繁加载 |
| SDIO(1-bit) | 1条数据线 | 0-50 MHz | ~50 Mbps | 高(CMD+CLK+DAT0) | SD卡、TF卡 |
| SDIO(4-bit) | 4条数据线 | 0-50 MHz | ~200 Mbps | 高(CMD+CLK+DAT0-3) | 高速SD卡、大文件批量读取 |
关键结论:LVGL加载图片时,瓶颈往往不在解码,而在接口带宽。一张800×480的RGB565图片约750KB,如果SPI跑20MHz,理论加载时间约120ms——实际加上协议开销,奔着200ms去了。用户滑动时明显卡顿。
SPI:最基础,但别小看它
SPI是入门首选。4根线(SCK、MOSI、MISO、CS),几乎所有MCU都支持。我最早做LVGL项目时,用的就是SPI接W25Q64。
优点:
- 引脚少,布线简单
- 驱动成熟,移植快
- 支持DMA,CPU开销低
缺点:
- 单线传输,带宽有限
- 半双工模式效率低
我的经验:SPI做LVGL图片加载,建议用DMA+双缓冲。我曾经在一个STM32F103项目上,SPI时钟跑到36MHz,配合DMA循环模式,加载320×240的JPEG图片(约30KB)耗时约15ms,用户体感还不错。但一旦分辨率上到480×320,就开始吃力了。
QSPI:LVGL加载图片的「黄金接口」
QSPI(Quad SPI)是我个人最推荐的接口。它本质上是SPI的升级版——4条数据线同时传输,时钟还能跑更高。
为什么QSPI适合LVGL?
- 带宽够:80MHz时钟下,理论480Mbps,实际约300-400Mbps
- 支持Memory-Mapped模式:Flash可以直接映射到MCU地址空间,CPU像读内存一样读Flash
- XIP(Execute In Place):代码可以直接在Flash上运行,省RAM
注意:QSPI的Memory-Mapped模式对MCU有要求。不是所有芯片都支持。比如STM32F4系列只有F469/479以上才带QSPI控制器。选型时一定要看数据手册的「QuadSPI」或「OSPI」章节。
我做过一个项目,用STM32H743的QSPI接W25Q256(32MB),时钟100MHz,Memory-Mapped模式。LVGL加载一张800×480的RGB565图片,耗时约6ms——几乎是瞬间显示。用户滑动列表时,图片切换完全无感。
SDIO:大容量场景的「重武器」
SDIO接口主要用于SD卡/TF卡。如果你需要存储大量图片(比如几百张高清图),SD卡是性价比最高的方案。
SDIO vs QSPI:
| 对比项 | SDIO(4-bit) | QSPI |
|---|---|---|
| 最大容量 | 2TB(SDXC) | 通常≤512MB |
| 随机读取 | 较差(文件系统开销) | 优秀(直接地址映射) |
| 持续读取 | 优秀(DMA+多块传输) | 优秀 |
| 驱动复杂度 | 高(需文件系统+协议栈) | 低(裸读写即可) |
| 功耗 | 较高 | 较低 |
避坑指南:我曾经在一个项目里用SDIO+FatFS加载图片,发现每次读取前都要先打开文件、定位、读取、关闭——这一套操作下来,光文件系统开销就占了30%的时间。后来改用「预打开+缓存文件句柄」的方式,才把延迟降下来。如果你用SD卡做LVGL图片存储,建议把常用图片的FAT表项缓存到RAM里。
接口选型决策树
说了这么多,到底怎么选?我画了个决策流程,你照着走就行。
实际项目中的接口选型建议
根据我这些年做过的项目,总结几条实战建议:
- 小项目(320×240以下,图片<50张):SPI足够。用W25Q16(2MB)或W25Q32(4MB),成本低,驱动简单。
- 中等项目(480×320,图片50-200张):QSPI是首选。W25Q128(16MB)或W25Q256(32MB),配合Memory-Mapped模式,体验很好。
- 大项目(800×480以上,图片>200张):SDIO+SD卡。建议用TF卡,容量选16GB以上。注意文件系统用exFAT(支持大文件)。
- 特殊场景(需要XIP):QSPI是唯一选择。代码和图片共用一片Flash,省PCB空间。
重要提醒:不管选哪个接口,LVGL的图片加载一定要用「异步+缓存」模式。我曾经见过有人直接在LVGL的刷新回调里同步读取Flash——结果界面卡成PPT。正确的做法是:用后台任务预加载图片到RAM缓存,LVGL直接从缓存读取。
接口驱动封装思路
最后聊一句驱动封装。我习惯把接口驱动抽象成三层:
- 硬件层:直接操作寄存器或HAL库,完成SPI/QSPI/SDIO的收发
- 传输层:封装成统一的读写接口,比如
storage_read(addr, buf, len) - 应用层:对接LVGL的文件系统接口或直接内存映射