
记得早年间第一次被领导按着头去查DDR初始化代码里的refresh相关寄存器时我满脑子都是“这不就是定时给电容充电吗有什么好查的”。结果板子在高温房里跑了一个小时随机出现位翻转排查了整整两天才把问题定位到tREFI配置和温度特性的匹配上。从那以后我对DRAM刷新这件事就不敢再“想当然”了。DRAM刷新refresh确实是基础中的基础但越基础的东西反而越容易被忽略。很多做嵌入式或者硬件设计的同学可能知道要配tREFI、tRFC但真要问一句“这个值是怎么来的”“温度变了会有什么影响”“为什么自刷新能省电”往往就说不清了。这篇作为系列基础小知识的第三篇就把贴吧、群里大家最常问的DRAM刷新问题好好归归类从原理到参数再到故障排查争取一次讲透。先给还没接触过这块的同学一句话概括DRAM靠电容上的电荷保存数据而电容会漏电所以必须定期给它们“续命”这个动作就叫刷新。下面我们就从“为什么会漏电”开始一步步拆开来看。1. 为什么要刷新电容漏电是根本原因1.1 一个存储单元只有“一个晶体管加一个电容”DRAM的存储单元结构极其简洁每个bit就是一个MOS管加一个电容业界叫1T1C。晶体管负责开关读写通道电容负责用有没有电荷来代表0和1。你可以把它想象成无数个微型水桶有水代表逻辑1没水代表逻辑0。问题就出在这个“水桶”上。DRAM里用的电容不是理想的储能元件它存在漏电流路径电荷会随着时间慢慢流失。这个漏电过程不是“瞬间”但在纳米尺度、微安级别的漏电流下几毫秒到几十毫秒内电荷量就足以衰减到无法分辨0和1的程度。所以DRAM不能像SRAM那样上电之后一劳永逸它必须赶在电荷衰减到临界值之前把数据读出来、放大、再写回去这就是refresh的基本动作。1.2 从“漏水的水桶”到“数据丢失”的推演这里有个非常容易混淆的点很多人以为refresh是“重新写一遍”其实标准做法是“读出来再写回去”而且这个过程对软件是透明的。更准确地说现代DRAM的刷新操作是由内存控制器或者DRAM内部状态机负责的CPU和操作系统感知不到。推演一下整个过程电容初始充满电荷存储逻辑1。时间推移漏电流让电荷减少。如果不做任何干预经过一个数据保留时间retention time电容上电荷量掉到无法被灵敏放大器正确判读的门限以下。这时候哪怕只是正常读一次读出来的可能已经变成0数据就永久丢了。数据保留时间通常在几十毫秒到几百毫秒之间工业界标准做法是保证在标准工作温度下所有存储单元至少能撑过规定的刷新周期典型值是64ms消费级DDR4/DDR3标准。64ms听起来不长但对现代内存控制器来说足够从容因为刷新是按行推进的不需要在同一瞬间照顾所有电容。1.3 温升与漏电的恶性循环温度对漏电流的影响是指数级的。JEDEC标准中标准刷新率比如64ms周期是基于正常工作温度范围的通常是0到85摄氏度的结温范围。超过这个温度漏电速度会明显加快数据保留时间随之缩短。实测中我最常见的现象是常温下跑压力测试一切正常到了高温环境或者机箱散热不良时开始出现偶发性的bit flip。这种问题最难查因为看起来像逻辑bug实际上就是refresh rate跟不上高温下的漏电速度。所以在选型阶段一定要确认芯片的刷新特性标称值尤其是工业级、车规级产品它们通常支持温度补偿刷新Thermal Compensated RefreshTCR也就是芯片内部感知温度变化后自动缩短刷新间隔。这种机制在消费级内存上不一定完整支持。2. 刷新到底是怎么执行的机制与命令2.1 三种经典刷新命令你至少要知道名字DRAM发展到现在刷新机制经过多轮演进命令接口上主要出现过三种RAS Only RefreshROR最古老的方式通过拉低RAS、保持CAS为高来触发行刷新。这在SDRAM之前的老异步DRAM上常见现在已经很少单独使用了。CAS Before RAS RefreshCBR先拉低CAS再拉低RAS触发器进入刷新态。它比ROR更高效不需要外部提供行地址刷新行地址由内部计数器自动产生。Auto Refresh自动刷新SDRAM及之后的DDR世代的标准操作。内存控制器直接发出REF命令DRAM内部自动完成一行或多行的刷新外部不需要关心具体刷新哪一行。现在的DDR4、DDR5、LPDDR系列基本都用Auto Refresh为主搭配Self Refresh自刷新实现低功耗场景。2.2 刷新命令的动作拆解行激活、预充电与内部计数器以Auto Refresh为例一次刷新动作几乎就是一次“隐形的行访问”内存控制器发出REF命令。DRAM内部地址计数器把当前要刷新的行地址送到行译码器。字线被激活这一行的所有存储单元的电荷被送到位线上经过灵敏放大器读出并放大。灵敏放大器把放大后的数据写回存储电容等于给这一整行“充满了电”。字线关闭执行预充电precharge为下一次刷新或正常读写做好准备。内部刷新计数器自增指向下一行。每一步都对应真实电路行为所以刷新并不是瞬间完成的它需要占用一段时间这就是tRFC的来源。这里特别要提醒一句刷新是针对“行”的。内存控制器只需要知道总行数和刷新周期不需要为每个bit单独操心。这也是为什么刷新操作对软件是透明的——你哪怕只是一个单字节的嵌入式系统也得完成全阵列的行刷新因为这是物理规律决定的。2.3 自动刷新与自刷新的分工Auto Refresh和Self Refresh是两套运作逻辑Auto Refresh是正常工作时使用的刷新方式由内存控制器主动发起CKE引脚保持高电平系统时钟正常运行。它的优点是可以精确控制刷新时机缺点是内存控制器要操不少心。Self Refresh则用于系统休眠、待机等低功耗场景。这时候CKE被拉低DRAM内部启动自己的振荡器和定时器按内部节奏自发完成刷新外部时钟甚至可以停掉。这样既保住了数据又省下了时钟翻转和接口电路的大量功耗。从嵌入式开发者的角度看如果你的产品有sleep模式并且sleep期间需要保留内存数据那一定要确认进入Self Refresh的时序是否正确。很多低功耗项目踩坑都踩在“睡下去容易醒来难”上——CKE低下去之后唤醒时的退出时序不对轻则数据损坏重则总线锁死。3. 刷新参数怎么算从tREFI到tRFC3.1 一个公式理解tREFI与刷新率的关系JEDEC标准里DRAM的刷新参数核心是两组刷新周期Refresh Interval和单次刷新操作耗时Refresh Cycle Time。以DDR4标准颗粒为例全阵列刷新周期64ms标准温度即保证在这个时间内所有行至少被刷新一次。总行数常见为8192行8K refresh。刷新间隔的均值tREFI 64ms / 8192 7.8125μs。也就是说内存控制器平均每7.8μs就得发起一次刷新命令。这个时间不是随意取的它是“总预留时间 ÷ 总行数”得到的工程折中。如果行数变成16KtREFI就要减半刷新频率翻倍。tRFC则是一次刷新命令从发出到完成所需的时间DDR4颗粒常见的tRFC在260ns到350ns之间具体看颗粒密度和工艺制程。密度越大单次刷新涉及的行越多tRFC越长。3.2 为什么不是所有时刻都在刷新脉冲式刷新需要注意7.8μs是平均间隔实际内存控制器不会机械地每隔7.8μs发出一次REF。它会把刷新请求聚合处理有时候把几次刷新合并成一批在总时间窗口内完成即可。这个策略叫“pulled-in”或“spread refresh”目的是减少刷新对正常读写带宽的冲击。如果严格按照每个tREFI点刷一次那些时间段内恰好发生密集读写请求时总线冲突会非常严重。所以实际系统中内存控制器里有一套刷新仲裁逻辑它维护一个刷新计时器在tREFI窗口内灵活选择发起刷新的时机甚至会提前累计刷新请求等到总线空闲或者命令队列允许时批量执行。这个机制对性能影响很大也是各家IP性能差异的隐藏原因之一。3.3 温度补偿刷新是怎么工作的前文提到高温下漏电加快需要缩短刷新周期。JEDEC标准定义了多种刷新周期档位标准模式全阵列周期64ms适用于0-85℃。高温扩展模式全阵列周期32ms适用于85-95℃。某些车规级颗粒还支持95℃以上的进一步缩短。实现温度补偿刷新的常见做法是DRAM芯片内部带温度传感器输出温度码流内存控制器读取后动态调整tREFI。比如温度超过阈值就把tREFI从7.8μs调整到3.9μs。如果你在做方案选型需要特别确认芯片是否支持温度补偿刷新。有些低成本颗粒为了节省片上温度传感器只支持固定刷新率必须按最高工作温度对应的最短刷新周期来跑。这样虽然稳妥但功耗会白白增加因为常温下也在用高温档的高频刷新。3.4 一个实际计算的例子假设一颗DDR4颗粒配置如下全阵列刷新周期64ms总刷新行数8192tRFC 260nstREFI 7.8125μs那么在1秒内STS名义上的刷新次数 1000ms / 64ms × 8192 128000次但用tREFI直接算也会得到接近127988次基本一致。而每次刷新占用260ns意味着每秒钟有128000 × 260ns 33.28ms花在刷新上。如果内存带宽利用率已经很高这额外的33ms就会造成不小的性能损失。这个数字看着不大但在高带宽、低延迟场景下每多1%的总线占用都可能引发连锁的延迟抖动。设计高性能系统时这33ms是会直接计入你的延迟预算的。4. 刷新对性能与功耗的影响看不见的“隐形杀手”4.1 刷新为什么会卡顿刷新惩罚刷新期间DRAM的bank往往处于预充电或激活状态中无法响应正常的读写请求。如果某一次刷新恰好落在关键路径上CPU的一条load指令可能就要多等几百纳秒。内存控制器一般会尝试通过刷新调度来错开峰值但遇到极端密集的访问模式仍然不可避免地出现延迟尖峰。这在实际调优中表现得非常明显。用AIDA64这类工具跑内存延迟测试时你偶尔会看到几个异常高的延迟点多半就是刷新撞上了访问请求。排队等待刷新完成后延迟从几十纳秒直接跳到几百纳秒。应对刷新惩罚的常见手段有增大内存控制器的命令队列深度让刷新的等待时间被后续命令掩盖。采用“刷新区间划分”把刷新任务拆成小块分散在多个tREFI窗口中而不是一次性刷新多行。使用伪通道pseudo channel或rank交错让一个rank在刷新时另一个rank继续响应请求。4.2 自刷新的功耗优势是怎么省出来的自刷新之所以省电根本原因在于它可以关闭外部时钟和大部分接口电路。DRAM内部只保留一个低频振荡器、刷新计数器和必要的灵敏放大器其他高速逻辑全部进入待机状态。LPDDR系列在低功耗场景下的Self Refresh功耗可以降到普通Active功耗的几十分之一。这也是手机、可穿戴设备、物联网设备在睡眠时能保持内存数据不丢的关键。不过Self Refresh也有它的代价因为外部时钟停了退出Self Refresh时需要重新锁定时钟延时可能达到几个微秒甚至更长。如果你的产品要求“毫秒级快速唤醒”这里就需要权衡是保持Auto Refresh花更多静态功耗还是进入Self Refresh牺牲唤醒时间。4.3 内存控制器刷新调度的策略维度现代内存控制器对刷新调度的优化远不止“定期发命令”这么简单。我见过的高端控制器至少会考虑三个维度时序窗口根据tREFI、tRFC、tRAS等参数寻找最优的命令插入时机。bank/rank状态优先在bank空闲时插入刷新避免打断正在进行的读写操作。服务质量QoS为高优先级请求预留带宽刷新尽量让路但又要保证不超时。这就像红绿灯配时既要保证车辆读写请求顺畅通过又不能一直不给行人刷新请求放行。配得好的控制器能把刷新对性能的影响压到很低配得粗暴的可能让整体性能掉好几个百分点。5. 常见问题与排查技巧实录5.1 刷新相关故障现象速查表下面的表格是我这些年排查过程中整理出来的看到类似现象时可以按图索骥故障现象可能原因排查方向运行一段时间后出现随机位翻转刷新周期配置过长或温度超出颗粒范围查看tREFI配置确认工作温度是否超标检查TCR是否生效系统休眠唤醒后内存数据异常Self Refresh进入/退出时序不对或供电不稳检查CKE低电平时序确认唤醒流程中时钟恢复是否完成内存带宽高负载时CRC报错刷新冲突导致读写命令被破坏调大内存控制器刷新调度缓冲或降低内存频率验证低温下出现初始化失败部分颗粒低温刷新与预充电时序不兼容升级颗粒固件/microcode调整tRFC等时序参数待机功耗异常偏高没有进入Self Refresh仍以Auto Refresh运行检查低功耗模式代码是否真正拉低CKE确认状态机切换条件5.2 一次真实的高温排查实录之前帮一个做边缘网关的朋友排查过一个典型问题。设备在空调房里一切正常搬到户外阳光直射环境后开始频繁报内存ECC错误。一开始都怀疑是静电或者电源问题后来把温度的权重调上来才恍然大悟。排查步骤基本是这样先确认内存芯片表面温度用热电偶实测有83℃接近85℃的临界点。查看颗粒型号的datasheet确认它是标准刷新率产品不支持TCR自动增强。查看固件里tREFI配置确认是按标准64ms周期配置的。定位到问题后最稳妥的解法是换成支持温度补偿刷新的工业级颗粒刷新周期可以自动缩短到32ms。短期内临时解法是手动把tREFI调整到3.9μs等效32ms全阵列周期牺牲部分性能换取稳定性。这个案例的教训是选型阶段如果产品使用环境可能超过85℃就不能只盯着“常温能跑”必须把刷新特性考虑进去。芯片标称的好不好和你的工况合不合是两回事。5.3 排查刷新问题的三个关键工具实战中除了示波器和逻辑分析仪还有三个免费的“软件工具”非常顶用memtest86跑内存稳定性测试能快速暴露位翻转问题但注意它默认测试时序未必覆盖高温场景。颗粒厂商的DSData Sheet和配套计算表很多厂商会提供Excel形式的时序计算工具填上频率、tREFI、tRFC就能自动计算余量强烈建议多利用。内存控制器的调试寄存器如果你用的是SoC内存控制器一般会暴露很多现场状态比如刷新计数、刷新增益、刷新延迟统计。定期读这些值可以量化刷新对性能的影响。6. 顺带说清两个易混概念DRAM、DDR、PSRAM的关系以及refresh token6.1 DRAM是总称DDR是其中之一PSRAM是“伪装者”很多刚入门的人会把DRAM和DDR画等号这个不太准确。DRAMDynamic Random Access Memory是一大类存储器的总称特点就是电容存储、需要刷新。它包含了历史上的SDRAM也包含现在的DDR系列DDR1到DDR5、LPDDR系列手机/平板、GDDR系列显卡、以及各种嵌入式DRAM。DDRDouble Data Rate是DRAM的一种接口标准它在一代SDRAM的基础上通过上下沿都传输数据的方式把吞吐量翻倍。所以“DDR内存”严格来说是“采用DDR接口的DRAM”。PSRAMPseudo SRAM就更有意思了。它的存储单元本质是DRAM需要刷新的物理特性逃不掉但芯片内部集成了刷新逻辑外部接口做得和SRAM一样简单——不需要外部控制器干预刷新直接像用SRAM一样读读写写就行。所以你可以这样理解DRAM是物理类别的总称DDR是DRAM的一种高速接口标准PSRAM是“内部用DRAM、外部装成SRAM”的混合体选型时如果主控不支持DDR控制器但需要大容量存储PSRAM常是一个折中方案。代价是访问速度通常低于DDR容量也没法做到很大。6.2 refresh token和内存refresh完全是两个世界的“refresh”开发应用的朋友可能对“Failed to refresh token: 400 bad request: invalid refresh_token: empty string”这类报错不陌生。这里的refresh token是OAuth 2.0等认证体系中的概念指的是一个用于换取新访问令牌的凭证字符串。报错信息说得很清楚“invalid refresh_token: empty string”——也就是客户端传了一个空字符串给服务端服务端自然不认。常见原因包括客户端代码里没正确保存refresh token内存被清掉了。请求参数名写错了服务端没拿到有效字段。refresh token过期或被服务端吊销返回的也是类似错误。某些SDK在持久化token时出现空值写库下次重启拿到空串。这跟DRAM refresh八竿子打不着唯一的共同点就是都叫refresh一个管的是电容上电荷的物理存续一个管的是会话凭证的逻辑续期。如果搜“refresh token”搜到一堆DRAM的资料别慌你的搜索词存在语义歧义换个角度搜就是了。写到最后的一点经验回到开头说的那次高温排错后来我养成了一个习惯每块板子第一次调内存时都会先把tREFI和tRFC按颗粒datasheet里的最保守值填上然后设计一个温度梯度测试确定系统实际工作温度后再决定要不要“优化”刷新参数换取极限性能。这个习惯帮我避免过好几轮半夜去实验室救火。DRAM刷新这件事本质上就是一句话你必须在电荷漏光之前把数据再充满。但从这个物理底线延伸出的参数计算、温度补偿、控制器调度、功耗设计、故障排查每一环都有足够多的细节等你踩一遍。这篇基础小知识先帮你把骨架搭好后面如果有机会再单独写几篇讲讲刷新调度算法的实现细节和LPDDR自刷新状态机的时序图欢迎持续关注。