SDRAM 工作流程
SDRAM 工作流程
上电初始化
上电后必须先执行初始化序列,否则器件无法正常工作:
步骤1: VDD 与 VDDQ 同时上电,同时启动时钟
步骤2: 等待至少 200us
步骤3: 发送 PRECHARGE ALL(预充电所有 Bank)
步骤4: 连续执行 8 次以上 AUTO REFRESH
步骤5: 执行 MRS,编程 CAS Latency、突发长度等
步骤6: 初始化完成,进入正常操作
状态机概览
SDRAM 的内部操作由状态机控制。从冷启动到正常工作,再到各种运行状态的转换关系如下:
stateDiagram-v2
[*] --> PWR_UP : 上电 (VDD+VDDQ+CLK)
PWR_UP --> PRE_ALL : 等待 >200µs
PRE_ALL --> AR_CYCLE : PRECHARGE ALL
AR_CYCLE --> MRS_INIT : 8次 AUTO REFRESH
MRS_INIT --> IDLE : Mode Register Set
IDLE --> ROW_ACTIVE : ACT (行激活)
IDLE --> REFRESH : AUTO REFRESH
IDLE --> MODE_REG : MRS (重配置)
ROW_ACTIVE --> READ : READ
ROW_ACTIVE --> WRITE : WRITE
READ --> IDLE : READ with AP (A10=H)
READ --> PRECHARGING : PRE / BURST STOP+PRE
WRITE --> IDLE : WRITE with AP (A10=H)
WRITE --> PRECHARGING : PRE (tDPL后)
PRECHARGING --> IDLE : tRP 超时
REFRESH --> IDLE : tRC 超时
MODE_REG --> IDLE : tMRD 超时
IDLE --> PWR_DOWN : CKE=Low + NOP
PWR_DOWN --> IDLE : CKE=High + NOP
IDLE --> SELF_REFRESH : CKE=Low + AR
SELF_REFRESH --> IDLE : CKE=High + NOP
状态时序图
{
signal: [
{ name: "CLK",
wave: "n.|....|.....|.........." },
{ name: "cnt_xx",
wave: "x8|8.8.|8.88.|8.......",
data:[">200us","20ns","70ns+7.8us(8)","2clk","cnt=0","50ns"] },
{ name: "cmd",
wave: "x4|4444|44444|4...",
data:["NOP","4'b0010","NOP","4'b0001","NOP","4'b0001","NOP","NOP","4'b0011","NOP"] },
{ name: "state",
wave: "x3|3.3..3.33..3...",
data:["PWAIT","PRCALL","AREF(8)","MRS","IDLE","ACT"] }
],
config: { hscale: 2 }
}
各状态简要说明:
- PWR_UP → PRE_ALL → AR_CYCLE → MRS_INIT:上电初始化链,必须严格执行,不可跳过任一阶段
- IDLE:所有 Bank 空闲,可接收 ACT / MRS / AUTO REFRESH 命令
- ROW_ACTIVE:指定 Bank 的一行已激活,行数据锁存于 SA 中(tRCD 后),此时可发 READ/WRITE
- READ / WRITE:突发读/写进行中,支持连续命令;A10=H 时突发结束后自动预充电回到 IDLE
- PRECHARGING:预充电中(tRP),关闭激活行、SA 数据回写阵列、位线均衡到 VDD/2
- REFRESH:自动刷新中(tRC),内部计数器产生行地址,无需外部提供
- MODE_REG:模式寄存器设置中(tMRD),编程 CL/BL/突发类型
- PWR_DOWN:时钟使能(CKE)拉低进入掉电,输入缓冲关闭以省电
- SELF_REFRESH:CKE 拉低进入自刷新,内部定时器异步自动刷新,保持数据不掉
读操作(时序)
以 CL=2、BL=4 为例:
- ACT:发出 Bank 地址 + 行地址 → 指定行被激活,行数据载入 SA(耗时 tRCD)
- 等待 tRCD(至少 2~3 个时钟周期)
- READ:发出 Bank 地址 + 起始列地址(A10=H 启用自动预充电)
- 等待 CL:读命令后经过 CL 个时钟周期,数据在 DQ 线上连续输出
- 突发结束:DQ 自动回到高阻态;若启用自动预充电,Bank 自动关闭回 IDLE
- 若未启用自预充电 → 手动发 PRE 命令关闭行(等 tRP 后可重新 ACT)
读数据延迟(CL)由 SDRAM 内部流水线决定——数据在 SA 中已经就绪,CL 只是内部同步输出所需的管道延迟。
{ signal: [
{ name: "CLK", wave: "p...................." },
{ name: "CMD", wave: "4.4.4.4.4.4.4.4.4.4", data: ["ACT","NOP","NOP","READ","NOP","NOP","NOP","NOP","NOP","NOP"] },
{ name: "DQ", wave: "8.8.8.8.8.8.4.4.4.4", data: ["","","","","","","D0","D1","D2","D3"] }
]}
CL=2、BL=4:ACT 后经 tRCD=3clk 等待再发 READ,CL 延迟后 DQ 输出 4 拍数据
写操作(时序)
以 BL=4 为例:
- ACT:激活目标 Bank 与行(同读)
- 等待 tRCD
- WRITE:发出 Bank 地址 + 起始列地址;数据与写命令同拍送入(写延迟 = 0)
- 后续数据每时钟沿送入,长度由 BL 决定
- 最后数据后需满足 tDPL(数据入到预充电 ≥ 2 时钟),再发 PRE 关闭行
{ signal: [
{ name: "CLK", wave: "p................." },
{ name: "CMD", wave: "4.4.4.4.4.4.4.4.4", data: ["ACT","NOP","NOP","WRITE","NOP","NOP","NOP","NOP","PRE"] },
{ name: "DQ", wave: "8.8.8.8.4.4.4.4.8", data: ["","","","D0","D1","D2","D3","",""] }
]}
BL=4:数据与 WRITE 命令同拍开始,PRE 在最后数据后 2 时钟(tDPL=2)
预充电(Precharge)
预充电的作用是关闭当前激活的行,为激活下一行做准备:
- 发出 PRE 命令(A10=H = 预充电所有 Bank,A10=L 配合 BA 选指定 Bank)
- 灵敏放大器中的数据被写回阵列(回写)
- 位线被均衡到 VDD/2(准备下次读取)
- 等待 tRP(预充电时间)后,Bank 回到 IDLE
为什么不能直接跨行访问? —— SA 中暂存的是当前行的数据,换行必须先写回旧行再加载新行。这就是 PRE → ACT 的必要性。
刷新(Refresh)
由于电容漏电,所有行必须在 64ms 内各刷新一次。对于 8192 行的 SDRAM:
- 平均每隔 64ms / 8192 = 约 7.8us 执行一次 AUTO REFRESH
- 每次 AR 刷新一行,行地址由内部刷新计数器自动产生(外部无需提供地址)
- AR 命令要求所有 Bank 处于 IDLE 状态(先 PRE ALL)
- AR 执行期间内部发生:行激活 → 灵敏放大器锁存 → 回写(等效于一次”读后写回”)
- 一次 AR 耗时约 tRC(60~63ns)
自刷新(Self Refresh):低功耗模式下,CKE 拉低进入自刷新,内部定时器自动周期刷新。退出后建议补发一次 AR。
Bank 交错读写示例
利用 4 个 Bank 流水线化访问,隐藏预充电延迟:
时间 → T0 T1 T2 T3 T4 T5 T6 T7 T8
Bank A: ACT RD RD PRE - - ACT RD ...
Bank B: - ACT - RD PRE - - - ...
Bank C: - - ACT - - RD PRE - ...
Bank D: - - - - ACT - - RD ...
DQ Bus: - - D0A D1A D0B D0C D1C D0D ...
- 每 Bank 保持一行激活,读完后预充电
- 当一个 Bank 在预充电(tRP)时,另一个 Bank 在传数据——总线无空闲