本节摘要:当图像帧、网络包这类数据量超过片内 BRAM 容量,就需要给 FPGA 挂上外部存储——主流选择是 DDR SDRAM。本节讲清 DDR 控制器要伺候的三件大事:时序训练(找对采样点)、突发传输(一次搬一大块)、周期刷新(防电荷泄漏),并给出带宽计算方法与存储控制器 IP 的选型要点。
想象一个画面:你的 FPGA 要缓存一帧 1080p 图像,1920×1080 像素 × 3 字节,约 6 MB。片内 BRAM 只有几 MB,放不下——你需要外挂内存。最常用的是 DDR SDRAM(双倍数据速率同步动态随机存储器),常见颗粒(DDR3/DDR4)单颗 512 MB 到数 GB,便宜量大。
但直接用逻辑去读写 DDR 颗粒,你会发现它远比片内 BRAM 难伺候:数据总线是双向的(同一组线读也是它写也是它),时序要求精确到皮秒量级,还要定期刷新防数据丢失。直接写逻辑控制它,几乎必败。所以工程上从不"手搓"DDR 控制,而是用存储控制器 IP:厂商提供的控制器 IP 内部实现了全部时序细节,对外只暴露一个友好的读写接口(通常是 AXI,第 6 章主角)。你的工作是理解控制器在"伺候"什么,以便配好参数、写好带宽预算。
DDR 颗粒和 FPGA 之间的走线延迟、温漂,会让采样时机偏离理想值。上电初始化时,控制器会做训练:先写已知图案、再读回比较,逐步调整时序参数(写校准、读校准、附加延迟),直到找到最佳采样点。这就是为什么每次上电 DDR 初始化都要花几十毫秒——它在"摸清这一批硬件的手感"。
训练一旦失败,现象很典型:内存读写偶发错误、系统间歇性崩溃,且和温度强相关(天冷天热表现不一样)。排查训练问题先看初始化日志里的训练结果,再查 PCB 走线长度匹配。
DDR 的读写单位是突发(Burst):一次命令就连续搬一组数据,通常 8 个字。为什么设计成一次搬一大块?因为每条读写命令都有固定开销(激活行、预充电、地址建立),分摊到越多数据上越划算。突发传输是 DDR 高带宽的命根子——小块零散读写是 DDR 的效率杀手,工程上把数据拼成大块再读写,带宽差距能到好几倍。
DDR 的存储单元是电容,电荷会漏,必须定期刷新(每行每隔 64ms 内刷新一遍),否则数据丢失。控制器内置刷新调度器,把刷新命令穿插在正常读写之间。刷新是 DDR 控制器最默默无闻但最不能断的工作——断刷几十毫秒,整片内存的数据就开始蒸发。
评估 DDR 方案够不够用,先算峰值带宽。公式:
带宽 = 数据总线宽度 × 有效时钟频率 × 2(DDR 双边沿)
举例:64 位总线、DDR3-1600(实际 I/O 时钟 800MHz,双边沿等效 1600MT/s):
峰值带宽 = 8 字节 × 1600 MT/s = 12.8 GB/s
但峰值永远达不到:刷新要占时间(约 2%~4%)、读写切换要损失(总线方向切换有死时间)、突发之间要补开销。工程经验值:实际可持续带宽约为峰值的 50%~70%。设计时按峰值一半做预算,余量才够。
| 数据流 | 数据量 | 频率 | 需要带宽 |
|---|---|---|---|
| 1080p 视频流 | 6 MB/帧 | 30 fps | 约 180 MB/s |
| 千兆以太网 | 125 MB/s | 满负荷 | 约 125 MB/s |
| 4 路摄像头 | 各 50 MB/s | 持续 | 200 MB/s |
| 合计 | 约 505 MB/s |
这个例子说明:日常多媒体负载几百 MB/s,一个 DDR3 接口的可用带宽高达 6~9 GB/s,带宽不是瓶颈,延迟和访问模式才是。真正吃掉带宽的是乱序小读写——随机访问时行激活开销巨大,实际带宽可能掉到峰值的 20%。所以 DDR 设计的核心不是带宽计算,而是把访问变成顺序大块。
厂商提供的存储控制器 IP(如 Xilinx MIG、Intel EMIF)是标准做法,选型看四点:
| 评估点 | 说明 |
|---|---|
| 支持的 DDR 标准 | DDR3/DDR4/DDR5,与板载颗粒匹配 |
| 总线接口 | AXI 还是专用接口,与系统总线衔接 |
| 时序校准支持 | 训练流程是否完备、有没有校准状态输出 |
| 资料与案例 | 该颗粒型号有没有现成配置、踩坑记录 |
验收存储子系统有标准动作:先跑内存测试(连续写读回、地址随机、边界扫描),全过再挂业务。别一上来就压业务负载——先确认内存本身干净,业务出问题才怪不到内存头上。
背景:一块新做的板子,DDR3 颗粒,用厂商控制器 IP 配置。验收目标:确认存储子系统在业务负载之前是干净的。
操作:第一步跑连续写读回——往 0 地址开始顺序写入递增数据,再读回比对,全对;第二步跑地址随机——随机地址写读回,重点覆盖跨 bank 边界和行边界;第三步跑边界扫描——最低地址、最高地址、4GB 环绕处(别名区域)各写一组特殊图案。前两步全过,第三步在最高地址附近发现偶发读回不一致。
结果:追查下来,是地址位宽配置多配了一位——控制器配置里地址宽度设成了比颗粒实际位宽多一位,最高地址区域映射到了不存在的空间,读回的是浮动数据。改正配置后重跑,三步全过。
解读:这次验证的价值在于把"内存本身"和"业务逻辑"分开。如果跳过内存测试直接挂业务,业务偶发错误会让人以为是逻辑 bug,排查方向全错。先证明内存干净,后面所有问题都归因明确。
变式:内存测试还该加两类用例——数据模式敏感性测试(全 0、全 1、交替 0x55/0xAA、伪随机序列,抓串扰与耦合问题)和温度敏感性测试(跑一段时间让板子升温,确认训练参数在温度漂移下仍稳)。这两类在量产板验证里几乎是标配。
💡 关键直觉:DDR 工程的核心不是"写代码",是"想清楚数据怎么聚成大块再搬"。带宽算得再漂亮,访问模式一乱,一切归零。
下一步进入第 6 章:外设和存储都接进来了,谁来当"总指挥"?SoC 片上系统——ARM 处理器与 FPGA 的深度联姻。