资讯详情

半导体存储器选型与调试:时序、片选、地址扩展及自检

📅 2026/10/29 19:02:06 | 华诺云谱 👁 阅读
半导体存储器选型与调试:时序、片选、地址扩展及自检
简介这份PPT课件面向学习计算机硬件与数字系统设计的师生系统梳理半导体存储器的工作原理与使用方法适合课堂讲授、期末复习与硬件入门查漏补缺。内容围绕ROM与RAM两大主线展开覆盖掩模ROM、PROM、EPROM及快闪存储器的特点SRAM与DRAM的存储机理和性能差异并延伸到存储器容量扩展的连接方法与用存储器实现组合逻辑函数的设计思路。压缩包内为1个PPT文件大小约5.15MB章节结构清晰配有定义、分类、电路框图和典型例题式讲解便于按“概述—ROM—RAM—容量扩展—组合逻辑”顺序快速定位知识点。目前已有143人学习可作为数字电路课程中存储器章节的配套讲义也可用于梳理ROM掉电不丢失、RAM易失及刷新等易混概念。1. 半导体存储器一颗芯片的时序决定了整个系统能跑多快调试一块数据采集板时采样率卡在 2 MSa/s 上不去CPU 占用不到三成逻辑分析仪抓了半天也没看出总线有什么问题最后定位到外部 SRAM 的地址访问时间 tAA 是 55 ns而总线一个读周期只留了 40 ns 给数据建立——每次读回来的都是上一次的数据程序却毫无察觉。这类问题在原理图和 BOM 上都不会暴露出来只会埋藏在半导体存储器的时序参数里。半导体存储器指的是用半导体工艺做成的存储阵列SRAM、DRAM、NOR Flash、NAND Flash、EEPROM、FRAM 全在这个家族里它们的共同点是都通过地址、数据、控制三组信号进行操作区别在于什么时候能读、什么时候必须等待、掉电之后数据还在不在。这一章要处理的不只是一门课的第七章而是从单片机外扩一片 SRAM到 SoC 挂载 DDR 颗粒的所有存储子系统设计——容量怎么计算、片选怎么译码、时序余量怎么留、出错时从哪里查。2. 容量、地址线与片选把「1M×8」拆成四个可接线的参数拿到一颗存储芯片的型号第一件事不是看封装而是把「1M×8」这串字符转换成四个硬件参数地址线根数、数据线根数、地址范围、片选条件。这四个参数决定 PCB 上究竟要走多少根线、译码器怎么接、软件里的指针能不能直接访问。2.1 存储矩阵、地址译码与三组总线的物理含义芯片内部本质上是一个二维阵列横向是字线word line纵向是位线bit line交叉点上的单元存 1 bit。片内的地址译码器把外部送进来的 n 根地址线翻译成 2^n 条字线中的一条被选中的那条字线上所有单元同时把数据放到各自的位线上再由灵敏放大器输出到外部数据引脚。所以「1M×8」的含义是阵列有 2^20 行、每行 8 个 bit 被同时读出需要 20 根地址线A0A19、8 根数据线D0D7一次访问交出一个字节。控制侧通常有三根关键信号片选 /CE有的器件叫 /CS只有它有效芯片才响应地址和数据输出使能 /OE控制数据引脚是输出还是高阻写使能 /WE下降沿锁存数据。异步 SRAM 靠这三根信号的电平组合完成读写没有时钟参与所以它的速度取决于地址变化到数据稳定要多久tAA、片选有效到数据稳定要多久tCE。同步器件则多一个时钟读写行为被绑在时钟沿上参数变成建立时间、保持时间和 CL 之类的周期数。理解了这一点接线时就不会把地址线和数据线的作用搞混地址线是「找到哪一行」数据线是「这一行取回几位」控制线是「什么时候取、往哪个方向取」。2.2 用一段脚本把容量、地址位宽和地址范围算清楚手工计算 512K×16 需要多少根地址线、地址空间跨到哪里是最容易出错的一步尤其是十六进制换算。我习惯先写一个小脚本把规格一次性算出来后面的接线表和软件里的地址宏都从这里生成避免同一组数字在两个地方写得不一样。import math def mem_spec(words: int, width: int, start: int 0x0000, step: int 1) - dict: words: 字数深度必须是 2 的幂如 1024、8192、120 width: 字长bit等于数据线根数如 8、16、32 start: 该段在 CPU 地址空间中的起始地址 step : 每个字占用的地址单元数8 位机取 132 位机按字访问时取 4 if words (words - 1): raise ValueError(字数必须是 2 的幂否则地址线无法直接对应) addr_lines words.bit_length() - 1 # log2(words)即地址线根数 span words * step # 该段占用的地址单元总数 end start span - 1 # 末地址 起始 容量 - 1 total_bits words * width # 总位数bit chips None # 由调用方补齐见 4.1 print(f{words:8} x {width:3} f地址线{addr_lines:2} 数据线{width:3} f容量{total_bits // 8:9} B 地址范围0x{start:06X} ~ 0x{end:06X} f 片内跨度0x{span:X}) return {addr_lines: addr_lines, end: end, bytes: total_bits // 8} for w, d in [(1 10, 8), (1 13, 8), (1 15, 8), (1 19, 16), (1 20, 8), (1 22, 32)]: mem_spec(w, d, start0x000000)这段代码的三个关键点。其一words.bit_length() - 1就是 log2避免浮点运算在 2 的幂边界上出现 19.9999 变成 19 的问题其二end start words * step - 1里的「减 1」是地址范围的定义决定的不是笔误其三step参数是很多人忽略的一项——在 32 位机里按字寻址时相邻两个 32 位字之间差 4 个字节地址如果step取 1算出来的地址范围会直接缩水到四分之一导致软件按 0x2000_0000 去写的时候其实写到了别的段里。跑出来的结果可以直接当接线依据119那行显示 512K×16 需要 19 根地址线、16 根数据线、1 MB 容量地址范围 0x0000000x0FFFFF。把这张表打印出来贴在调试台前比反复按计算器靠谱。2.3 地址范围与片选的边界末地址为什么总比容量小 1初学者最容易写错的不是地址线根数而是末地址。一个 1K×8 的存储段标注成 0000H0400H看上去「刚好一千」实际是 1025 个单元多出来的那一个会和下一段的首地址重叠形成典型的地址冲突。正确写法是 0000H03FFH因为 1024 个单元从 0 开始编号最后一个编号是 1023即 0x3FF。把常见容量的对应关系记牢比背公式有用字数地址线根数8 位机字节容量起始 0000H 时的末地址1K101 KB03FFH8K138 KB1FFFH32K1532 KB7FFFH64K1664 KBFFFFH512K19512 KB7FFFFH1M201 MBFFFFFH4M224 MB3FFFFFH这张表的规律是末地址的每一位都是 F位数等于容量对应的十六进制位数。1M 是 16 进制的 0x100000末地址就是 0xFFFFF。而地址线根数则决定片选译码要做到哪一位——如果系统有 24 根地址线16 MB 空间只用 A19A0 进行译码那么这片 1 MB 的存储器会在 0x000000、0x100000、0x200000……共 16 个位置重复出现这被称为地址镜像。提示故意利用镜像有时是合理的比如用地址高位做多份固件备份但前提是在头文件里写清楚每一份镜像的基地址否则等到用 DMA 搬运数据时就会遇到数据写进去但读不回来的问题。判断是否做全译码的标准很简单如果系统里还有别的外设挂在同一组数据线上那么未参与译码的高位地址必须被用起来通过译码器或反相器排除掉不能省事地悬空。3. SRAM、DRAM、NOR Flash、EEPROM按场景选型的对照与边界选型时常见的误区是只比较容量和单价。存储器的实际使用成本由访问方式、擦除粒度、寿命和接口开销共同决定一颗便宜的 NAND 可能因为写放大把 CPU 占满一颗贵的 SRAM 反而能把整个系统的实时性保住。3.1 六类半导体存储器的关键参数对照下面这张表按「读怎么写、写怎么擦、掉电还剩不剩」三条主线来整理参数取常见量级具体型号还要回到自己的数据手册上核对。类型存储单元读访问量级写/擦粒度掉电保持主要代价异步 SRAM6 管单元1055 ns单字无擦除无每 bit 六个晶体管容量小、单价高同步 SRAM6 管单元 输出寄存器按周期计几 ns 到十几 ns单字无需要时钟、流水线接口复杂DRAM1 管 1 容行激活后十几 ns单字经行缓冲需周期性刷新必须有控制器行列地址复用NOR Flash浮栅器件70120 ns 随机读块擦几十 KB 级、字/页写十年以上写慢、擦除寿命有限、写放大明显NAND Flash浮栅器件页读 25100 μs页写、块擦数百 KB 级十年以上存在坏块需要 ECC 与磨损均衡EEPROM浮栅器件几百 ns 到 μs字节写十年以上写慢擦写寿命约百万次量级FRAM / MRAM铁电 / 磁阻几十到上百 ns字节写无擦除概念十年以上容量小、单价高、温度窗口相对窄表格里最容易被低估的是「写/擦粒度」这一列。读访问时间决定了系统能不能实时运行而擦写粒度决定了十年后这块板子还能不能正常写数据。3.2 三种典型场景的选型推演场景一带外部总线接口的 MCU 外扩数据缓冲。需要几十 KB 到 1 MB 的随机读写空间写入频繁不能有擦除等待掉电丢数据无所谓。这里的答案是异步 SRAM原因不是速度快而是接口最省心地址、数据、/CE、/OE、/WE 直接挂到总线上不需要控制器、不需要初始化序列、不需要刷新。要留的余量是时序——把 tAA 与总线的读周期留出 30% 以上的裕量温度从 25 ℃ 降到 -40 ℃ 时多数器件的访问时间会变慢一到两成。场景二大容量缓存动辄几百 MB成本敏感。只有 DRAM 可选代价是整个存储子系统从「接几根线」变成「做一套控制器」行列地址复用、刷新调度、写入训练、端接匹配、PCB 等长。这里有个现实的边界判断——如果团队里没有人做过 DDR 的板级调试第一版就把 DRAM 放在主板上风险远高于把这块需求交给带存储控制器的现成模块。场景三存固件、参数和掉电不能丢的日志。三项需求对应三种不同的器件。固件要能被 CPU 直接取指执行选 NOR Flash支持随机读可以直接映射到地址空间参数区小、改写次数不多但要求按字节更新选 EEPROM日志区数据量大、写入频繁选 NAND Flash 并配套文件系统和磨损均衡。如果参数区每天要改写上万次EEPROM 的百万次寿命两三年就会耗尽此时换 FRAM 是更省心的方案单价换寿命账算得过来。3.3 选型时最容易忽略的三个隐藏成本第一个是写放大。NAND 的最小擦除单位是块哪怕只改一个字节也要把整块读出来、改一个字节、擦掉整块、再写回去。一个 4 KB 的日志块如果每秒钟被改一次实际写入量就是每秒 4 KB 以上再加上磨损均衡的搬移寿命消耗比账面数字快得多。计算寿命时应该用「总擦除次数 × 块容量 ÷ 实际日写入量」而不是简单看 datasheet 上的擦写次数。第二个是电平与总线负载。3.3 V 器件接到 5 V 总线上需要电平转换转换芯片本身有传播延迟几纳秒看似不多但对 55 ns 的读周期来说就是 10% 的余量。另外多片并联时数据线上的容性负载会把上升沿拉缓这时候串一个 2233 Ω 的源端匹配电阻往往比换一颗更快的芯片有效。第三个是温度与刷新。DRAM 的刷新周期在高温下要缩短很多器件的 datasheet 会给出常温与高温两套刷新间隔软件里如果只写了一组参数夏天机房温度上来后就会偶发位翻转。这类故障最不像硬件问题程序跑得好好的某个计数器偶尔跳变一次查上几天也查不出原因。4. 位扩展与字扩展8 片 SRAM 挂上总线的最小接线与译码单颗芯片的容量和位宽几乎永远对不上需求所以真实的存储子系统都是多片组合出来的。组合只有两种基本动作位扩展和字扩展剩下的都是这两种的叠加。4.1 位扩展和字扩展到底在扩什么位扩展解决的是「字长不够」。用两片 1M×4 拼成 1M×8两片的地址线全部并联、片选 /CE 并联、写使能并联区别只在数据线——第一片接 D0D3第二片接 D4D7。这样一次访问会同时选中两片各自贡献 4 bit合起来就是一个字节。位扩展不增加地址线只增加数据线。字扩展解决的是「字数不够」。用四片 1M×8 拼成 4M×8四片的数据线全部并联到 D0D7地址线 A19A0 也全部并联区别在片选——由高位地址 A21、A20 经译码器产生四根互斥的片选任何时刻只有一片被选中。字扩展不增加数据线只增加地址线。真实需求往往是两者同时缺。举一个完整的例子手上有 8 片 512K×8 的异步 SRAM要组成 1M×32 的存储体。先算需求1M 字需要 20 根地址线32 位需要 32 根数据线。再算单片能力512K 字只需要 19 根地址线8 位数据线。差距是字长 8→324 倍、字数 512K→1M2 倍正好 4×28 片一片不多一片不少。接线方案每一组 4 片做位扩展共用 A18A0 和同一根片选分别负责 D0D7、D8D15、D16D23、D24D31两组之间做字扩展用 A19 产生两根片选。第一组占 00000H7FFFFH第二组占 80000HFFFFFH。提示位扩展时最容易犯的错误是把不同组的数据线接反尤其是 32 位总线上 D0D31 的排列。布线完成后先用走位图测试确认每一位都对应正确再焊接其余器件否则后面查错时就要一层一层剥。4.2 74LS138 译码与片选接线从地址空间到物理连线译码器的职责是把若干根高位地址线翻译成一根低有效的片选信号。74LS138 是 3-8 译码器三个输入 A、B、CC 是最高位三个使能端 G1高有效、/G2A、/G2B低有效八个输出 /Y0/Y7 低有效。它的真值等价于当使能全部满足时输出编号等于输入组成的二进制数只有那一路被拉低。在一个 24 位地址空间16 MB的系统里用 138 做全译码把 1 MB 当作一个基本段分成 8 段接线如下138 引脚接到作用C / B / AA22 / A21 / A20三位输入选择 8 个 1 MB 段之一G1高位地址译码有效信号如 A23 经反相后的高电平高有效使能确保只在目标窗口内工作/G2A系统复位信号或另一根地址线低有效用于排除不想要的区域/G2B总线存储器请求 /MREQ只有真正访问存储器时才使能避免误选中/Y0/Y7各段存储体的 /CE低有效片选一段一路接好之后若第一段是存储体 0占 000000H0FFFFFH1 MB第二段 Y1 对应 100000H1FFFFFH依此类推。回到 4.1 的 1M×32 例子如果系统只有 1 MB 空间A19 就不必经过 138直接一根线接第一组 /CE、经一个反相器接第二组 /CE 即可只有当地址空间远大于存储容量、并且总线上还挂着别的外设时才值得用 138 把整个空间切干净。判断译码方案是否正确的标准有三条任何时刻至多一根片选有效每根片选对应的地址范围互不重叠所有用到的地址位都参与了译码或被明确记录为「故意镜像」。4.3 用脚本生成地址映射表并做重叠校验段一多接线表就会写乱两个人对着同一份 Excel 各接各的最后在地址 0x80000 处撞车。我一般在接线前先跑一个映射校验脚本把每一段的起始、容量、片选来源列出来让程序检查重叠、空洞和对齐。segments [ # name, start, size(字节), 片选来源 (BANK0_WORD32, 0x000000, 0x100000, Y0), (BANK1_NOR, 0x100000, 0x080000, Y1), (BANK2_EEPROM, 0x180000, 0x001000, Y2), ] def check(segs): segs sorted(segs, keylambda s: s[1]) for i, (name, start, size, cs) in enumerate(segs): if size (size - 1): print(f[对齐] {name} 容量 0x{size:X} 不是 2 的幂片选无法直接译码) if start % size: print(f[对齐] {name} 起始 0x{start:X} 未按容量 0x{size:X} 对齐) end start size - 1 print(f{name:14} 0x{start:06X} ~ 0x{end:06X} size0x{size:7X} CS{cs}) if i 1 len(segs): nxt_start segs[i 1][1] if end nxt_start: print(f [重叠] 与 {segs[i1][0]} 冲突重叠 0x{end - nxt_start 1:X} 字节) elif nxt_start - end 1: print(f [空洞] 0x{end1:06X} ~ 0x{nxt_start-1:06X} 未分配) print(地址总跨度 0x{:X}.format( max(s[1] s[2] for s in segs) - min(s[1] for s in segs))) check(segments)脚本做了四件事按起始地址排序保证比较的是相邻段检查容量是否为 2 的幂因为片选译码的前提是地址位直接对应检查起始地址是否按容量对齐未对齐的段没法用一根地址线直接选中最后检查相邻段之间是否重叠或有空洞。重叠是致命的空洞大多是浪费但两者都会在调试时表现为「读到了不该读的数据」而不会报错。参数上要注意size用的是字节数如果某段是按 32 位字组织的容量换算成字节时乘 4起始地址也要按 4 对齐否则校验脚本会误报对齐错误。5. 避坑与排查半导体存储器调试现场 5 条血泪记录存储器的故障有个共同特点它很少直接崩溃多数表现为数据偶发不对、程序跑飞、参数莫名恢复默认。这类问题如果只靠单步调试往往查不出原因。5.1 现象上电后整片读出来全是 FF 或全是 00现象初始化代码里写 0x55 再读回读到的却是 0xFF 或 0x00换几块板子现象一致。原因排第一的是片选根本没被拉低。译码器的使能端接反G1 接到了低电平或者 /G2A 悬空被拉高芯片永远处于未选中状态数据引脚一直是高阻被总线上的上拉电阻拉成 FF另一种情况是 /OE 与 /WE 接反读的时候芯片其实在写。解决先用示波器看 /CE 引脚在读周期里有没有出现低脉冲没有就往前查译码器使能有低脉冲再看 /OE 与 /WE 的时序关系。若片选正常但数据仍是 FF把数据总线上的上拉电阻暂时去掉看读数是否变成随机值——如果还是 FF说明芯片没在驱动总线如果变成乱码说明总线被别的东西占用了。5.2 现象低半段地址读写正常高半段读出来是低半段的镜像现象往 0x00000 写 0x11、往 0x80000 写 0x22读 0x80000 却得到 0x11改 0x00000 的值0x80000 跟着变。原因是高位地址线没参与译码。1M 容量的存储体只用到 A19A0如果系统地址空间是 4 MBA21、A20 悬空或者被直接接地那么 0x000000、0x100000、0x200000、0x300000 四个位置全部映射到同一块物理存储形成四份镜像。看起来像「高地址不生效」本质上是地址别名。解决把未使用的高位地址全部引入译码器或者至少要保证它取某个确定值并且把这个约束写进注释。已经做好的板子如果改不了线在软件层把访问范围限制在第一个 1 MB 内并在头文件里显式说明镜像区的存在能避免后续维护者误用。5.3 现象写入后回读固定某一位不对换数据也一样现象写 0x00 读回 0x08写 0xFF 读回 0xF7永远是 D3 这一位不跟随数据变化。原因通常是数据线接错位或者虚焊。八根数据线里D3 与相邻的地址线或地线短路或者焊接时错位一格表现为该位恒为 0 或恒为 1。另一种可能是该位所在的 I/O 缓冲配置成了推挽输出却没有切换方向读的时候它仍在向外驱动。解决用走位图测试逐位确认——对同一个地址依次写入 0x01、0x02、0x04……0x80每写一次回读一次哪一位不动就是哪一位的硬件问题。这个方法比看波形快得多尤其在 QFP 封装上探针够不着的时候。5.4 现象常温下跑一整天没问题机箱温度上来后偶发数据错误现象老化测试前两小时正常之后每隔十几分钟出现一次校验失败断电重启又恢复。这是典型的时序余量不足或刷新不及时。异步器件的 tAA 随温度升高而变慢原本 30 ns 的余量在 70 ℃ 时可能只剩 5 nsDRAM 的高温刷新间隔比常温短一半如果控制器里只写了一组刷新参数高温下就会出现漏刷导致的位翻转。电源纹波也属于同一类——大电流瞬变时 VCC 掉一下写进去的数据就变成了半电平。解决先量时序用示波器同时抓 /OE 下降沿到数据有效的间隔与数据手册在同温度下的限值比较留出的余量应该不少于一个总线周期的 25%。再查刷新把控制器的刷新周期按器件的最高工作温度配置不要用常温值。最后看电源在存储器电源引脚旁边就近加 0.1 μF 与 10 μF 的组合单独一路供电不与电机、继电器共用。5.5 现象Flash 写入偶尔失败参数区隔几天恢复成默认值现象参数写入返回成功第二天上电发现变回出厂值用调试器看那块区域是 0xFF。原因多半是写前没整块擦除或者擦除过程中掉电。NOR/NAND 的写操作只能在已擦除全 1的单元上把 1 变成 0无法把 0 变回 1若目标块之前写过别的数据而没有擦除写入的结果就是新旧数据按位与看起来写了一部分。掉电中断更隐蔽擦除到一半掉电整块数据都变成不确定状态。解决写入流程改成「读-改-擦-写」四步并把整个流程做成可重入的先写备份区校验通过后再写主区主区带 CRC。参数区不要只存一份双备份加分区的做法能挡掉绝大多数掉电损坏。另外擦写次数要记录下来估算剩余寿命别等到擦坏了才发现。6. 上电自检与回归把存储子系统做成一套可重复执行的测试动作存储器最麻烦的地方在于它坏的时候不会报警只会悄悄返回错误数据。所以我在每个用到外部存储器的项目里都会固定做三件事并让它们在上电时自动跑一遍。第一件是数据线走位图只针对一个单元覆盖短路、开路、驱动不足#include stdint.h /* 在一个单元上做数据线走位先逐位写 1再逐位写 0 */ int data_bus_walk(volatile uint32_t *cell) { for (int b 0; b 32; b) { *cell 1u b; if (*cell ! (1u b)) return b; /* 第 b 位拉不高 */ *cell ~(1u b); if (*cell ! ~(1u b)) return 32 b; /* 第 b 位拉不低 */ } return -1; /* 全部通过 */ }第二件是地址唯一性覆盖地址线虚焊、译码错误和地址镜像。做法是每个字写入自己的地址值再回读比对出错时返回偏移量能直接定位到哪一根地址线有问题/* 每个字写入自身地址再回读返回第一个不匹配的字偏移-1 表示通过 */ int addr_uniqueness(volatile uint32_t *base, uint32_t words) { for (uint32_t i 0; i words; i) base[i] (uint32_t)(base i); for (uint32_t i 0; i words; i) if (base[i] ! (uint32_t)(base i)) return (int)i; return -1; }第三件是棋盘格与全 0/全 1 交替覆盖相邻单元之间的耦合。三项的判定标准与覆盖范围可以整理成一张表测试项覆盖的故障判定标准数据线走位数据线短路/开路、驱动不足32 位全部通过返回 -1地址唯一性地址线虚焊、译码错误、镜像全容量通过返回 -1棋盘格0x5555/0xAAAA相邻位线、字线耦合全容量回读一致参数区 CRC掉电损坏、擦写寿命耗尽CRC 匹配失败则从备份区恢复跑这三项的时间成本要提前算1 MB 的存储体做一次地址唯一性测试大约是两百万次读写在 55 ns 的器件上不到一秒完全可以放进上电流程但如果是几十 MB 的 DRAM就要按抽样比例执行只在产线全检时跑全量。我自己的习惯是把这三项做成一个可配置开关的模块量产固件里只保留参数区 CRC 抽样地址测试把耗时压到 50 ms 以内开发阶段则打开全量测试每次改完时序参数或换料都跑一遍。有次就是因为换了批次的 SRAMtAA 从 45 ns 变成 55 ns全量测试在高温箱里报出地址唯一性失败才没有让问题流到现场。存储器这种东西后悔药从来都是提前吃的。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑