3. 存储器选型与系统设计:Flash、SRAM、SDRAM、DDR、eMMC、NAND Flash
存储器的选型,说白了就是给嵌入式系统选「记忆体」。选错了,轻则性能瓶颈,重则系统跑不起来。我见过不少项目,硬件工程师把DDR走线画得漂漂亮亮,结果软件一跑就死机——最后发现是容量算错了,或者接口时序没对齐。
这一章,咱们把嵌入式系统里常见的存储器挨个捋一遍。从容量计算到接口选择,我会把实际项目中的坑和经验都抖出来。
3.1 存储器的层级与角色
嵌入式系统里的存储器,不是随便堆的。它们有明确的层级关系。你想想看,CPU跑得飞快,Flash却慢得像蜗牛,中间必须有个缓冲。
核心原则:速度越快的存储器,成本越高,容量越小。系统设计就是在成本和性能之间找平衡。
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,能省引脚就省引脚。但每个项目都不一样,关键是把需求搞清楚,再动手选。