3. 存储器选型与系统设计:Flash、SRAM、SDRAM、DDR、eMMC、NAND Flash

存储器的选型,说白了就是给嵌入式系统选「记忆体」。选错了,轻则性能瓶颈,重则系统跑不起来。我见过不少项目,硬件工程师把DDR走线画得漂漂亮亮,结果软件一跑就死机——最后发现是容量算错了,或者接口时序没对齐。

这一章,咱们把嵌入式系统里常见的存储器挨个捋一遍。从容量计算到接口选择,我会把实际项目中的坑和经验都抖出来。

3.1 存储器的层级与角色

嵌入式系统里的存储器,不是随便堆的。它们有明确的层级关系。你想想看,CPU跑得飞快,Flash却慢得像蜗牛,中间必须有个缓冲。

核心原则:速度越快的存储器,成本越高,容量越小。系统设计就是在成本和性能之间找平衡。

嵌入式系统存储器层级结构 CPU寄存器 SRAM(片内/片外) SDRAM / DDR(主内存) NAND Flash / eMMC(大容量存储) NOR Flash(代码存储) 层级特点 ↑ 速度越快 ↑ 成本越高 ↓ 容量越小 SRAM:纳秒级访问 DDR:百兆到千兆带宽 NAND:毫秒级读写 NOR:可直接执行(XIP)

3.2 Flash存储器:NOR vs NAND

Flash是嵌入式系统的「硬盘」。但Flash分两种:NOR和NAND。很多人搞混,我刚开始做项目时也吃过亏。

3.2.1 NOR Flash

NOR Flash的特点是支持XIP(eXecute In Place),也就是说CPU可以直接从NOR Flash里取指令执行,不用先拷到RAM里。启动代码放NOR里,上电就能跑。

  • 优点:读取快,随机访问性能好,可靠性高
  • 缺点:写入慢,容量做不大(一般64Mb~512Mb),价格贵
  • 典型用途:Bootloader、固件存储、少量参数保存

我的经验:做工业控制器时,我习惯把关键配置参数放在NOR Flash的最后几个扇区。万一固件升级失败,参数还在,系统还能恢复。这个习惯救过我一次——有一次OTA升级到一半断电,重启后设备靠NOR里的备份参数自动恢复了运行。

3.2.2 NAND Flash

NAND Flash容量大、价格低,但不能直接执行。它天生就有坏块,需要ECC纠错和坏块管理。说白了,NAND就是个「不靠谱」的存储介质,得靠软件来兜底。

  • 优点:容量大(几GB到几TB),写入快,单位成本低
  • 缺点:有坏块,需要ECC,读取速度一般,不支持XIP
  • 典型用途:文件系统、大容量数据存储、多媒体文件
对比项 NOR Flash NAND Flash
读取速度 快(随机访问) 一般(页读取)
写入速度 慢 快
擦除速度 慢(块擦除) 快(块擦除)
坏块 极少 有,需要管理
XIP支持 支持 不支持
典型容量 1Mb ~ 512Mb 1Gb ~ 1Tb
每MB成本 高 低

3.3 eMMC:把NAND封装成「黑盒子」

eMMC说白了就是把NAND Flash和一个控制器封装在一起。控制器帮你处理了坏块管理、磨损均衡、ECC纠错。你只需要通过标准的MMC接口读写就行了。

我个人非常推荐在Linux嵌入式系统里用eMMC。省心。不用自己写NAND驱动,不用管坏块,文件系统直接挂载。我做过一个项目,原来用裸NAND,光坏块管理就折腾了两周。后来换成eMMC,一天搞定。

注意:eMMC虽然省心,但有个坑——它的寿命是有限的。写入次数到了,整个芯片就废了。做日志系统或频繁写入的应用时,一定要算好寿命。我曾经有个项目,设备每天写日志100MB,结果eMMC半年就挂了。后来改成先写RAM再批量刷入,问题解决。

3.4 SRAM:速度至上

SRAM是静态随机存取存储器。速度快,纳秒级访问,但容量小、价格贵。一般用在CPU片内Cache,或者作为片外高速缓冲。

什么时候需要片外SRAM?

  • MCU内部RAM不够用,但又需要高速访问
  • 实时性要求高的数据缓冲(比如图像处理、音频处理)
  • 低功耗场景(SRAM待机功耗极低)

接口选择:片外SRAM一般用并行接口(地址线+数据线)或SPI接口。并行SRAM速度快但占引脚多,SPI SRAM引脚少但速度慢。我一般只在需要大容量缓冲时才用并行SRAM,否则用MCU内部RAM就够了。

3.5 SDRAM与DDR:系统的主内存

SDRAM和DDR是嵌入式系统的「工作台」。代码从Flash搬到SDRAM里运行,数据在DDR里处理。没有它,跑不了复杂应用。

3.5.1 SDRAM

SDRAM是同步动态随机存取存储器。它在时钟上升沿传输数据。速度一般在100MHz~166MHz。老一些的ARM9、Cortex-A系列还在用。

3.5.2 DDR SDRAM

DDR是双倍数据速率SDRAM。它在时钟上升沿和下降沿都传输数据,所以带宽翻倍。从DDR1到DDR5,速度越来越快,电压越来越低。

类型 数据速率 电压 典型应用
SDRAM 100~166 MT/s 3.3V 低端ARM9、老系统
DDR1 200~400 MT/s 2.5V 早期Cortex-A
DDR2 400~800 MT/s 1.8V 中端嵌入式Linux
DDR3 800~2133 MT/s 1.5V 主流嵌入式、树莓派
DDR4 1600~3200 MT/s 1.2V 高性能嵌入式

PCB走线警告:DDR的走线不是闹着玩的。DDR3以上,等长、阻抗、参考平面,一个都不能少。我曾经见过一个团队,DDR3走线差了2mm,结果系统跑800MHz就死机。降频到600MHz才稳定。嗯,硬件工程师被骂了一周。

3.6 容量计算:别拍脑袋

容量计算是系统设计的第一步。我见过太多人「先选个大的再说」,结果成本超了,或者性能浪费了。

3.6.1 代码存储容量

代码放NOR Flash或eMMC里。怎么算?

固件大小 = 代码段 + 数据段 + BSS段 + 文件系统开销
实际选型 = 固件大小 × 1.5 ~ 2(留余量)

举个例子:你的固件编译出来是4MB,加上文件系统2MB,总共6MB。选型时至少选16MB的NOR Flash。为什么?因为还要留空间给OTA升级包、日志、配置参数。

3.6.2 运行内存容量

运行内存(SDRAM/DDR)的容量计算更复杂。我一般这么算:

内存需求 = 操作系统内核 + 应用程序 + 数据缓冲 + 显示帧缓冲 + 网络协议栈 + 安全余量

举个实际案例:一个带LCD显示的Linux系统:

  • Linux内核:~8MB
  • 应用程序:~16MB
  • 帧缓冲(1024×600×32bit):~2.5MB
  • 网络缓冲:~4MB
  • 其他:~4MB
  • 总计:~35MB

选型:64MB DDR2。留一半余量,够用。

我的习惯:内存容量至少留30%~50%的余量。系统跑起来后,内存使用率会慢慢涨——内存泄漏、新增功能、数据量变大,这些都是不可预见的。我吃过亏:一个项目选了32MB,结果客户要求加功能,内存不够,只能换芯片重新做板子。成本翻倍。

3.7 接口选择:匹配总线与带宽

存储器接口的选择,取决于你的CPU/MCU支持什么,以及你的带宽需求。

存储器 常用接口 带宽 引脚数
NOR Flash SPI / Quad SPI / 并行 ~50MB/s (QSPI) 6~30
NAND Flash 并行NAND接口 ~40MB/s ~24
eMMC MMC/SDIO ~400MB/s (HS400) ~12
SRAM 并行 / SPI ~100MB/s (并行) ~30
SDRAM 并行SDRAM接口 ~1.6GB/s (32bit@100MHz) ~50
DDR3 并行DDR3接口 ~8.5GB/s (32bit@1066MHz) ~60

选接口时,我一般遵循这个原则:

  • 代码存储:QSPI NOR Flash,引脚少,速度够用
  • 大容量存储:eMMC,省心,接口简单
  • 主内存:DDR3/DDR4,带宽高,但PCB设计复杂
  • 高速缓冲:并行SRAM,但只在必要时用

总结一下:存储器选型没有银弹。你得根据系统需求——速度、容量、成本、功耗、PCB复杂度——来权衡。我个人的经验是:能用eMMC就别用裸NAND,能用DDR3就别用SDRAM,能省引脚就省引脚。但每个项目都不一样,关键是把需求搞清楚,再动手选。