前面写了很多 NAND 的内容,从 Cell、Program、Erase,到 Read、Read Retry、Multi-Plane,这些内容大多是在讲 NAND 内部发生了什么。

但如果把视角往外拉一步,会遇到一个更基础的问题:SSD Controller 到底是怎么和 NAND 通信的?

Controller 想让 NAND 执行 Read、Program 或 Erase,需要把 Command 发给 NAND;想访问某个 Page,需要把 Address 告诉 NAND;真正读写数据的时候,又需要把 Data 在 Controller 和 NAND 之间传输。而这些事情,最终都要通过 NAND 芯片外面的一根根引脚完成。

所以这一篇,我们先不往 NAND 内部走,而是从 NAND 的引脚说起。

一、先认识NAND的几个基本引脚

不同厂商、不同代际、不同 Interface Mode 的 NAND,具体 Pin 定义会有所区别。如果先从最基本的 NAND 接口来看,常见的几组信号包括:

  • • CE#:Chip Enable,用来选择 NAND
  • • CLE:Command Latch Enable,用来指示当前 DQ 上的是 Command
  • • ALE:Address Latch Enable,用来指示当前 DQ 上的是 Address
  • • WE#:Write Enable,用来配合锁存 Controller 送进 NAND 的内容
  • • RE#:Read Enable,主要用于控制 NAND 的数据输出
  • • R/B#:Ready/Busy,用来告诉 Controller NAND 当前是 Ready 还是 Busy
  • • WP#:Write Protect,用于 Program、Erase 的写保护
  • • DQ[7:0]:Data I/O,用来传输 Command、Address 和 Data

这些信号里,这篇文章真正想讲的是 DQ[7:0]、CLE 和 ALE。因为只要仔细看这组 Pin,就会发现一个很奇怪的问题:

NAND 的地址引脚去哪了?

二、NAND的地址引脚去哪了?

我们已经知道,NAND 内部有很多 Block,每个 Block 里又有很多 Page。Controller 想读取某一份数据,首先必须告诉 NAND:我要访问的是哪一个位置。

这个“位置”,本质上就是 Address。

在很多数字存储器或者数字芯片里,这类位置信息通常会通过专门的 Address Pin 送进去。比如 A0、A1、A2、A3……这些引脚共同组成 Address Bus,地址中的每一位通过不同的 Address Pin 送入芯片,芯片再根据这些地址信息选择内部对应的位置。

如果按照这种思路来看,NAND 既然同样需要区分不同的 Block、Page,以及 Page 内部的位置,似乎也应该有一组专门的 Address Pin。

但是再看 NAND 的 Pinout,却会发现:并没有 A0、A1、A2……这样一组独立的 Address Bus。

那 NAND 的地址到底从哪里送进去?

答案是:还是从 DQ[7:0] 进去。

而且不只是 Address。Command 也是从 DQ[7:0] 进去的,真正的 Data,同样还是通过 DQ[7:0] 传输。

也就是说,同样这一组 DQ,在不同时间承担了三种工作:Command、Address、Data。

这时候问题就来了:既然都是从 DQ 进去,NAND 怎么知道现在 DQ 上的是 Command,还是 Address?

这就是 CLE 和 ALE 存在的意义。

三、CLE和ALE到底是干什么的?

CLE 的全称是 Command Latch Enable,ALE 的全称是 Address Latch Enable。

当 Controller 要发送 Command 时,会让 CLE 处于有效状态。这时候 NAND 就知道,当前 DQ[7:0] 上的内容应该被当成 Command。

如果接下来 Controller 要发送 Address,则让 ALE 有效。NAND 就知道,当前 DQ[7:0] 上的内容应该被当成 Address。

所以可以简单理解成:

CLE 有效:DQ[7:0] → Command
ALE 有效:DQ[7:0] → Address
Data 阶段:DQ[7:0] → Data

这里有一点很重要:CLE 和 ALE 本身并不传 Command 和 Address。

真正承载这些信息的,还是 DQ。CLE 和 ALE 更像是在告诉 NAND:现在应该怎样理解 DQ 上的内容。

这也是为什么它们叫 Latch Enable。

四、以一次Read为例

拿一次最基本的 NAND Read 来看会更直观。

首先,Controller 要告诉 NAND:我要执行一次 Read。于是先通过 DQ 发送 Read Command,此时 CLE 有效。

接下来,Controller 还需要告诉 NAND:我要读哪里。于是进入 Address 阶段,这时候 ALE 有效,DQ 上开始依次传输 Address。

这些 Address 通常还会继续分成 Column Address 和 Row Address。这里先简单理解就可以:Column Address 决定 Page 内部的位置,Row Address 决定要访问哪一个 Page。

Address 发送完成之后,NAND 才会开始执行内部 Read。等内部 Read 完成以后,真正的数据再通过 DQ 返回给 Controller。

所以单纯从接口这一层看,一次 Read 大致可以理解成:

Command
↓
Address
↓
NAND内部Read
↓
Data

有意思的地方就在这里:前面的 Command、Address,以及最后真正的数据,走的其实都是同一组 DQ,只是发生在不同时间。

五、为什么不直接多搞一些引脚?

看到这里,很自然会产生另一个问题:既然 Command、Address 和 Data 本来就是三种不同的信息,为什么不干脆给它们各自准备独立的线路?

比如 Data Bus 一组,Address Bus 一组,Command Bus 再来一组。这样想发 Command 就走 Command Bus,想发 Address 就走 Address Bus,想传 Data 就走 Data Bus,不是更直接吗?

从电路上说,当然可以。

但问题在于:不划算。

NAND 的地址并不短。随着 NAND 容量不断增大,需要区分越来越多的 Block 和 Page,完整地址会越来越长。如果把这些 Address Bit 全部做成独立物理引脚,再给 Command 单独准备一组线路,那么整个 NAND 的 Pin Count 会明显增加。

而现在这种方式,只需要一组 DQ,再加上 CLE 和 ALE,就可以让 Command、Address 和 Data 共用同一套物理线路。

所以 CLE 和 ALE 看起来像是额外增加了两根控制线,但实际上它们的作用恰恰是:

用很少的控制 Pin,省掉更多专用 Pin。

六、为什么这种复用特别适合NAND?

如果只是为了少几根 Pin,其实还不足以解释为什么这套设计会长期存在。更关键的是,Command、Address 和 Data 的传输量根本不在一个数量级上。

一次 NAND 操作开始时,Controller 需要发送的可能只是少量 Command 和少量 Address,但后面真正传输的数据,却可能是一整个 Page。

也就是说,一次操作大致是:

少量 Command
↓
少量 Address
↓
NAND内部操作
↓
大量 Data

真正需要大量接口带宽的是 Data。Command 和 Address 只在一次 Operation 开始时短暂出现。

如果为了这些只使用几个 Cycle 的信息,长期准备一整套独立的 Address Pin 和 Command Pin,那么在真正大量传输 Data 的时候,这些 Pin 大部分时间都处于闲置状态。

这就不太划算。

NAND 于是选择了另外一种方式:让低占用率的 Command 和 Address,与 Data 共用 DQ。

付出的代价,是多花几个 Cycle 发送 Command 和 Address;换来的,则是更低的 Pin Count。

这其实是一种很典型的工程取舍:

用少量时间,换长期存在的硬件资源。

七、容量越来越大,为什么Pin没有跟着一直增加?

地址复用还有一个很实际的好处。

假设 NAND 使用独立 Address Bus,那么 NAND 容量增大以后,需要更多 Address Bit。Address Bit 增多,就可能意味着 Address Pin 也要继续增加。这样每次 NAND 容量升级,都可能影响封装、Controller 和 PCB。

但地址复用以后就不一样了。

NAND 内部可以继续增加更多 Block、更多 Page、更大的地址空间,而外面仍然可以继续使用原来的 DQ[7:0]。

地址变长怎么办?

很简单:多发一个 Address Cycle。

所以 NAND 内部容量增加以后,并不一定需要同步增加外部 Address Pin。

某种程度上可以说:

地址复用把 NAND 内部容量增长和外部 Pin Count 解耦了。

这对于 NAND 这种容量不断增长的存储器件非常重要。

八、为什么不同厂家后来都愿意这么做?

再往后想一步,还会有一个问题:如果这只是某一家 NAND 厂商的设计选择,为什么后来很多厂商都采用了类似的接口思路?

一开始,原因很简单:这种设计本身就适合 NAND。 它减少了 Pin Count,又没有付出太大的性能代价。

但等越来越多 NAND、Controller、封装、PCB、测试设备都围绕这种接口设计以后,事情就不只是“省 Pin”这么简单了,这时候又多了一个更重要的价值:

兼容性。

试想一下,如果每家 NAND 厂商都有完全不同的接口,A 厂使用独立 Address Bus,B 厂使用 DQ 复用,C 厂又使用另一套 Command Bus,D 厂的 Pinout 和 Timing 全都不一样,那么 Controller 厂商就要为不同 NAND 准备不同的接口。

SSD 厂商换一颗 NAND,可能连 PCB、Controller Pinout 和测试平台都要跟着变,整个产业链的成本都会明显增加。

反过来,如果大家在最基本的接口思路上保持一致,例如 DQ、CLE、ALE、CE#、RE#、WE#、R/B# 等基本信号保持类似,那么即使不同 NAND 在具体 Command、Timing、Feature 上仍然存在差异,至少最底层的连接方式可以保持相对稳定。

所以这套设计一开始是一个合理的工程选择,后来则进一步变成了整个产业链共同的接口基础。

九、后来有了ONFI和Toggle

随着 NAND 速度不断提高,接口也需要继续演进。

但真正需要解决的问题并不是:要不要把 Address 单独拉出来?

而是:

怎样让 DQ 上的数据传得更快?

于是后来的 NAND Interface 开始不断提高 I/O Rate,引入 DDR、DQS 等高速传输机制。现在经常看到的两套主要接口体系,就是 ONFI 和 Toggle Mode。

这里有一点很容易误解。

并不是 ONFI 或 Toggle 发明了 CLE、ALE,也不是它们发明了 DQ 复用 Command、Address 和 Data。这些基本接口思想在更早的 NAND 中就已经存在了。

ONFI 和 Toggle 更像是在这套基本结构上继续解决接口如何标准化、数据如何高速传输、Timing 如何定义,以及高速模式如何工作等问题。

所以即使 NAND 从早期异步接口一路发展到后来的高速 DDR 接口,仍然能看到熟悉的 CLE、ALE 和 DQ。

变化最大的,是 Data 的传输方式越来越快,而不是重新增加一大排独立 Address Pin。

十、从几个引脚,看NAND的设计取舍

如果只看 datasheet,我们很容易把:

CLE = Command Latch Enable
ALE = Address Latch Enable

记下来,然后继续往后看。

但如果多问几个为什么,就会发现,这两个 Pin 后面其实藏着 NAND Interface 很完整的一套设计逻辑。

为什么需要 CLE 和 ALE?因为 Command 和 Address 都没有独立的总线,而是和 Data 共用 DQ。CLE 用来告诉 NAND 当前 DQ 上的是 Command,ALE 用来告诉 NAND 当前 DQ 上的是 Address。

为什么三者要共用 DQ?因为 Command 和 Address 的传输量很小,而真正占用接口带宽的是后面大量的数据。既然 Address 和 Command 只在少数几个 Cycle 出现,就没有必要为它们长期准备大量独立物理线路。

于是 NAND 做了一个很典型的取舍:

少量额外的 Command / Address Cycle

换

更少的物理引脚

这种设计不仅减少了 Pin Count,也让 NAND 容量继续增长时,不需要让 Address Pin 数量跟着不断增加。

后来 NAND 接口一路发展到 ONFI、Toggle,速度越来越高,DQS、DDR 等机制不断加入,但 CLE、ALE 和 DQ 复用这种基本思想一直被保留了下来。

因为真正需要大量带宽的,从来都不是前面那几个 Byte 的 Command 和 Address。

而是后面真正要传输的那些数据。

 

谢谢你看我的文章