4. 读写命令时序:ACTIVATE、READ、WRITE、PRECHARGE、REFRESH 命令的时序关系
好,咱们直接切入正题。DDR 的读写操作,说白了就是一套“开行 -> 读写 -> 关行”的流程。你想想看,DDR 内部就像一个巨大的表格,行地址就是行号,列地址就是列号。你要读写数据,得先激活一行,然后才能操作这一行里的某个列。
我刚开始调 DDR 的时候,总觉得这些命令就是按顺序发就行了。结果呢?时序总是不对,数据读出来全是乱的。后来才明白,每个命令之间都有严格的时序要求,差一个时钟周期都不行。
4.1 核心命令速览
先快速过一遍这几个命令是干嘛的:
- ACTIVATE (ACT):激活一行。说白了就是把某一行打开,让这一行的数据准备好被读写。
- READ:从已激活的行中读取数据。
- WRITE:向已激活的行中写入数据。
- PRECHARGE (PRE):预充电。关闭当前激活的行,为下一次激活做准备。
- REFRESH (REF):刷新。DDR 需要定期刷新来保持数据,这个命令会强制关闭所有行并刷新。
核心原则:ACTIVATE 和 PRECHARGE 必须成对出现。你激活了一行,用完了就必须关掉,否则下一轮操作就没法进行。
4.2 时序关系详解
4.2.1 ACTIVATE 到 READ/WRITE:tRCD
这是最关键的参数之一。tRCD(RAS to CAS Delay)指的是从发出 ACTIVATE 命令到可以发出 READ 或 WRITE 命令之间的最小延迟。
为什么会这样?因为激活一行需要时间,行地址选通后,数据要从存储单元传输到 sense amplifier(感测放大器),这需要时间。你发 READ 命令太早,数据还没准备好,读出来的就是垃圾。
我个人习惯在调试时,先把 tRCD 设成数据手册推荐的最大值,确保功能正确,然后再慢慢往下压,找到最优值。
避坑指南:我曾经遇到过一块板子,常温下 tRCD 设成 10 没问题,但一跑到高温环境就出错。后来发现是温度变化导致延迟变了。所以,一定要留余量,别卡着极限值。
4.2.2 READ 到 PRECHARGE:tRTP
读操作完成后,不能立刻发 PRECHARGE 命令。你需要等一段时间,让数据完全从存储阵列中读出来。这个时间就是 tRTP(Read to Precharge)。
你想想看,如果你在读数据还没完成时就关了行,那后面的数据就丢了。嗯,这里要注意,tRTP 通常和突发长度有关。比如突发长度为 8,那 tRTP 至少得覆盖这 8 个数据的读取时间。
4.2.3 WRITE 到 PRECHARGE:tWR
写操作完成后,同样不能立刻关行。tWR(Write Recovery Time)是写数据到存储单元后,需要等待数据稳定下来的时间。
说白了,就是数据写进去了,但还没完全“固化”到存储单元里。你提前关行,数据可能就写丢了。我见过不少新手在这里栽跟头,写操作看起来成功了,但读回来发现数据不对,就是 tWR 没给够。
4.2.4 PRECHARGE 到 ACTIVATE:tRP
预充电命令发出后,需要等待 tRP(Row Precharge Time)才能再次激活新的一行。预充电的过程是关闭当前行,并准备好下一行的激活。
这个时间取决于 DDR 的物理特性。你发 PRE 命令太早,下一行还没准备好,ACTIVATE 就会失败。
4.2.5 REFRESH 的特殊性
REFRESH 命令比较特殊。它本质上是一个“自动预充电 + 自动刷新”的过程。当你发出 REFRESH 命令时,DDR 内部会自动完成所有行的刷新操作。
关键点在于:REFRESH 期间不能有任何其他操作。你必须等 REFRESH 完成(通常需要 tRFC 时间)才能继续发 ACTIVATE 或 READ/WRITE 命令。
警告:REFRESH 命令的间隔是固定的(比如 7.8μs),你必须在这个时间内完成所有刷新操作。如果系统负载太高,来不及刷新,数据就会丢失。我曾经在一个高带宽项目中,因为刷新占用了太多时间,导致读写带宽不够。后来通过调整刷新策略(比如用“刷新后立即激活”的技巧)才解决。
4.3 典型读写时序流程
咱们用一个实际的例子来串一下。假设你要读 DDR 中的数据:
- ACTIVATE:发 ACT 命令,指定行地址。等待 tRCD。
- READ:发 READ 命令,指定列地址。数据会在 CAS Latency (CL) 个时钟后出现在数据总线上。
- 等待数据读完:根据突发长度,等待所有数据返回。
- PRECHARGE:发 PRE 命令,关闭当前行。等待 tRP。
- ACTIVATE:可以激活下一行了。
写操作类似,只是把 READ 换成 WRITE,并且需要等 tWR 才能发 PRE。
4.4 时序参数汇总表
| 参数 | 全称 | 说明 | 典型值 (DDR4-3200) |
|---|---|---|---|
| tRCD | RAS to CAS Delay | ACT 到 READ/WRITE 的延迟 | 14-16 个时钟周期 |
| tRTP | Read to Precharge | READ 到 PRE 的最小间隔 | 7-8 个时钟周期 |
| tWR | Write Recovery Time | WRITE 到 PRE 的最小间隔 | 10-12 个时钟周期 |
| tRP | Row Precharge Time | PRE 到 ACT 的最小间隔 | 14-16 个时钟周期 |
| tRFC | Refresh Cycle Time | REFRESH 命令的持续时间 | 350-550 个时钟周期 |
4.5 核心时序关系图
下面这张图展示了 ACTIVATE、READ、PRECHARGE 之间的时序关系。我特意把关键参数标出来了,你调试的时候可以对照着看。
4.6 调试中的常见问题
我总结几个实际调试中容易踩的坑:
- tRCD 不够:ACT 后立刻发 READ,数据全是 0 或随机值。解决办法:检查 tRCD 是否满足数据手册要求。
- tWR 不够:写数据后立刻发 PRE,再读回来发现数据没写进去。解决办法:增加 tWR 的值。
- REFRESH 冲突:在 REFRESH 期间发了其他命令,导致系统死锁。解决办法:确保 REFRESH 期间命令总线空闲。
- tRTP 被忽略:读操作后立刻发 PRE,导致最后几个数据丢失。解决办法:计算好 tRTP,确保所有数据都读完了再关行。
我的调试习惯:先用 DDR 控制器自带的训练功能,让它自动校准这些时序参数。然后手动读回训练结果,看看控制器选了哪些值。如果发现它选的值偏小,我会手动加 1-2 个时钟周期作为余量。
好了,这一章的内容就到这里。记住,DDR 的时序调试没有捷径,就是对照数据手册,一个一个参数去验证。你调得多了,自然就有感觉了。