硬件接口基础: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里。

接口选型决策树

说了这么多,到底怎么选?我画了个决策流程,你照着走就行。

外部存储接口选型决策流程 开始选型 图片数量 < 100张? 单张 < 200KB? 是 否 SPI / Dual SPI 低分辨率,小容量 QSPI 中等容量,高频率加载 分辨率 > 480×320? 加载频率高? 容量 > 64MB? 需要热插拔? 是 否 是 否 升级到QSPI 或使用JPEG硬件解码 保持SPI方案 优化DMA和缓存策略 SDIO(4-bit) 大容量,可插拔 提示:如果MCU支持QSPI Memory-Mapped模式,优先选QSPI SDIO适合需要超大容量或热插拔的场景

实际项目中的接口选型建议

根据我这些年做过的项目,总结几条实战建议:

  1. 小项目(320×240以下,图片<50张):SPI足够。用W25Q16(2MB)或W25Q32(4MB),成本低,驱动简单。
  2. 中等项目(480×320,图片50-200张):QSPI是首选。W25Q128(16MB)或W25Q256(32MB),配合Memory-Mapped模式,体验很好。
  3. 大项目(800×480以上,图片>200张):SDIO+SD卡。建议用TF卡,容量选16GB以上。注意文件系统用exFAT(支持大文件)。
  4. 特殊场景(需要XIP):QSPI是唯一选择。代码和图片共用一片Flash,省PCB空间。

重要提醒:不管选哪个接口,LVGL的图片加载一定要用「异步+缓存」模式。我曾经见过有人直接在LVGL的刷新回调里同步读取Flash——结果界面卡成PPT。正确的做法是:用后台任务预加载图片到RAM缓存,LVGL直接从缓存读取。

接口驱动封装思路

最后聊一句驱动封装。我习惯把接口驱动抽象成三层:

  • 硬件层:直接操作寄存器或HAL库,完成SPI/QSPI/SDIO的收发
  • 传输层:封装成统一的读写接口,比如 storage_read(addr, buf, len)
  • 应用层:对接LVGL的文件系统接口或直接内存映射