NAND Interfaces: ONFI, Toggle, and the Speed Problem
For most of NAND flash’s history, the slow part was the cell. Pulling charge out of a floating gate, sensing it against a reference, and resolving which of sixteen voltage levels a QLC cell holds takes tens of microseconds, and that page-read time, tR, dominated every datasheet conversation. That era is ending. Modern triple-level and quad-level NAND still has a tR of roughly 50 to 90 microseconds, but the array reads a 16 KB page in one shot, and once that page sits in the on-die register the only thing standing between it and the controller is a parallel bus running at a fixed transfer rate. As that bus has crawled from 50 MB/s to 4.5 GB/s the math has inverted: for a large sequential read, the time spent shoveling bytes across the interface now rivals or exceeds the time spent reading the cells. The bottleneck moved off the silicon and onto the wire. This post is about that wire — the two standards that define it, the punishing signal-integrity physics that limits it, and why the industry’s answer is not “make the bus faster” so much as “put fewer things on each bus and build more buses.”
Two standards for the same problem
A NAND die exposes a deceptively simple parallel port: an 8-bit data bus (DQ[7:0]), a handful of control strobes (chip enable, command latch enable, address latch enable, write enable, read enable), and a ready/busy line. You assert a command, clock in addresses, and the die either accepts write data or streams read data back over the same eight wires. The early interface was asynchronous single data rate (SDR): the controller toggled the read-enable signal, and the die put one byte on DQ per edge. It topped out around 40 to 50 MB/s, which was fine when the cell was the bottleneck and capacities were small.
Two camps decided to fix it, and they did not agree on how. The Open NAND Flash Interface working group — driven by Intel, Micron, Hynix, SanDisk, and Spansion — published ONFI 1.0 in 2006 and modeled its high-speed evolution closely on DRAM, borrowing DDR signaling conventions wholesale. Toggle Mode, developed by Samsung and Toshiba (now Kioxia), took an alternate route: it kept the asynchronous character of the original interface, dispensing with a free-running clock, and instead used a bidirectional data strobe (DQS) to time transfers, with the command itself establishing direction. Crucially, Toggle Mode evolved through customer-specific datasheet releases rather than public standards documents, while ONFI published unified, openly available specifications. The two are electrically similar enough that controller PHYs routinely support both, but they are not interchangeable, and the split persists today: roughly speaking, Micron, SK Hynix, and the old Intel lineage speak ONFI, while Samsung and Kioxia/Western Digital speak Toggle.
The deeper point is that both standards converged on the same physics. Once you commit to double-data-rate transfers and gigahertz-class edge rates, you are forced into the same toolbox — a source-synchronous strobe, differential signaling, on-die termination, and per-lane calibration — regardless of whose logo is on the package. The branding diverges; the silicon problems do not.
The climb from SDR to source-synchronous DDR
The first real break from the legacy interface was source-synchronous DDR. Instead of the controller blindly toggling read-enable and hoping the data arrived in time, the die now sends a strobe — DQS on ONFI, DQS on Toggle — alongside the data, generated from the same internal timing as the data itself. The receiver captures DQ using DQS rather than its own clock. This matters enormously: when strobe and data travel the same path and are launched by the same source, they share most of their delay, and the timing relationship between them stays stable even as the absolute delay grows. ONFI calls its DDR mode “NV-DDR” (the NV is for non-volatile), and the generations track DRAM’s nomenclature: NV-DDR, NV-DDR2, NV-DDR3.
Here is the rough progression, by ONFI revision and signaling generation:
| ONFI rev | Signaling | Max rate | Key additions |
|---|---|---|---|
| 1.0 | Async SDR | ~50 MT/s | Standardized command set, base parallel bus |
| 2.0 | NV-DDR | 133 MT/s | First DDR transfers, double-edge sampling |
| 2.1/2.2 | NV-DDR | 200 MT/s | Higher rate, warmup cycles |
| 3.0/3.1 | NV-DDR2 | 400 MT/s | Differential DQS/RE#, ODT, VREF, single-ended |
| 3.2 | NV-DDR2 | 533 MT/s | Rate bump |
| 4.0 | NV-DDR3 | 800 MT/s | Per-pin training framework |
| 4.1 | NV-DDR3 | 1066/1200 MT/s | Low-power enhancements |
| 4.2 | NV-DDR3 | 1600 MT/s | Rate bump |
| 5.0 | NV-DDR3 | 2400 MT/s | NV-LPDDR4 introduced |
| 5.1 | NV-DDR3 / NV-LPDDR4 | 3600 MT/s | WDCA, per-pin VrefQ, equalization, asymmetric DQS |
| 5.2 | NV-DDR3 / NV-LPDDR4 | 3600 MT/s | Separate Command Address protocol, errata |
The per-channel bandwidth math is worth doing in plain numbers, because it is where the “speed problem” becomes concrete. An 8-bit (x8) channel transfers one byte per data beat, and MT/s is mega-transfers per second:
bytes_per_second = (transfers_per_second) x (bus_width_bits / 8)
NV-DDR @ 200 MT/s , x8: 200e6 x 1 byte = 200 MB/s
NV-DDR2 @ 533 MT/s , x8: 533e6 x 1 byte = 533 MB/s
NV-DDR3 @ 1600 MT/s, x8: 1600e6 x 1 byte = 1600 MB/s (1.6 GB/s)
NV-DDR3 @ 2400 MT/s, x8: 2400e6 x 1 byte = 2400 MB/s (2.4 GB/s)
NV-DDR3 @ 3600 MT/s, x8: 3600e6 x 1 byte = 3600 MB/s (3.6 GB/s)
A 1 MB/s of every 1 MT/s on an x8 bus — that is the whole conversion. The transfer is the easy part to reason about. Getting clean edges at 3600 MT/s into a stacked package full of capacitive loads is the hard part, and it is where most of the engineering now lives. For background on how the bits got onto the die in the first place, see how data lives on platters and flash and 3D NAND architecture.
What read and write training actually do
At 200 MT/s you could get away with fixed timing. At 3600 MT/s you cannot, because the valid data window — the slice of time during which DQ is stable and capturable — has shrunk to a couple hundred picoseconds, and the natural skew between lanes, between DQ and DQS, and between dies exceeds that window. The fix is training: before normal operation (and periodically afterward), the controller and die run a handshake that measures and compensates for these mismatches lane by lane.
There are two halves, read training and write training, and inside each there are two distinct jobs:
DQS __ __ __ __
\/ \ / \ / \ / \
/\ /\ /\ /\ /\ /\ /\
DQ lane (untrained) X==X X==X X==X X==X edges scattered, DQS not centered
^ ^
| +-- DQS edge lands near data transition = unreliable capture
step 1: DESKEW align every DQ lane's edges to a common reference
step 2: CENTER delay DQS so its edge sits in the MIDDLE of the data eye
DQS ____ ____ ____
\ / \ / \
DQ lane (trained) X======X======X======X all lanes aligned
^ ^ ^
+------+------+--- DQS sampling at eye center = robust
Read deskew sets a per-lane delay element so that the rising edges of every DQ bit line up, undoing the fact that each of the eight bits took a slightly different path length through the package and board. Read centering then delays DQS relative to the now-aligned DQ so that the strobe edge falls in the center of the valid data eye rather than near a transition. Get this wrong by a few tens of picoseconds at 3600 MT/s and you sample garbage.
The other axis is Vref training, or VrefQ calibration. DDR signaling compares each incoming bit against a reference voltage to decide whether it is a one or a zero. As edge rates climb and signaling voltages drop, the optimal threshold drifts — and it drifts differently per pin because of asymmetric loading and crosstalk. ONFI 5.x added per-pin VrefQ adjustment precisely so the receiver can dial in an independent reference voltage on each lane, opening the vertical extent of the data eye. ONFI 5.1 piled on still more: Write Duty Cycle Adjustment (WDCA) to fix the asymmetry where the high and low halves of the strobe are not equal width, plus equalization (including decision-feedback equalization, which subtracts the lingering tail of the previous bit from the current sample) and an asymmetric DQS design to cope with the unequal rise and fall behavior of real drivers. None of this is optional cleverness; at these rates a raw, untrained link simply does not close. This calibration-against-physics theme runs throughout flash — the array side has its own analog of it, which I cover in calibrating flash at the factory and in the analog margins discussed in the NAND read window budget.
The multi-drop bus and the tyranny of capacitance
Here is the geometry that makes all of this hard. A flash channel is not a point-to-point link. To get density, manufacturers stack many dies into a single package — commonly 8 or 16 dies, vertically wire-bonded — and hang several of those packages off one controller channel. All of those dies share the same DQ wires; only one transmits or receives at a time, selected by chip-enable, but all of them are electrically connected to the bus all of the time. This is a multi-drop topology, and it is the worst case for high-speed signaling.
Every die you add to the shared bus adds input capacitance. The driver — whether the controller on writes or a die on reads — has to charge and discharge that lumped capacitance on every edge. The more capacitance, the slower the edges; the slower the edges, the smaller the valid window at a given data rate. Worse, each stub where a die taps the bus is an impedance discontinuity, and at gigahertz edge rates those discontinuities launch reflections that bounce up and down the bus and arrive back at the receiver as intersymbol interference, smearing the data eye closed. A 16-die stack is sixteen stubs and sixteen capacitive loads on one shared transmission line, inside a package a few millimeters tall.
CONTROLLER
|
[ channel 0 DQ[7:0] + DQS ] <-- one shared multi-drop bus
| | | |
die0 die1 die2 ... die15
|C |C |C |C <-- each die = capacitive load + stub
| | | |
reflections add up; only ONE die drives at a time, all 16 load the line
Two techniques fight back. On-die termination (ODT), introduced with NV-DDR2, places a switchable resistor inside each die that can be turned on to absorb energy at the bus ends and damp reflections — the controller enables ODT on the dies that are not actively transmitting so they act as terminators rather than reflectors. Differential signaling for DQS and read-enable (also from NV-DDR2 onward) makes the strobe far more immune to common-mode noise and ground bounce than a single-ended line. Both help. Neither repeals the underlying scaling law: capacitance and stub count rise linearly with dies-per-channel, and the achievable data rate falls as a result. A practical illustration from the literature: a 32-die shared channel is essentially unworkable at meaningful speeds with conventional techniques, because the aggregate load drags the bus down faster than the extra capacity is worth.
Why the channel, not the cell, now bounds throughput
Put the two halves together. The cell side delivers a page after tR; the interface side then drains that page at the bus rate. For a single read of one 16 KB page:
tR (TLC, typical) ~= 60 us (cell -> on-die register)
transfer 16 KB @ 1200 MT/s (x8) = 16384 bytes / 1200 MB/s ~= 13.6 us
transfer 16 KB @ 2400 MT/s (x8) = 16384 bytes / 2400 MB/s ~= 6.8 us
single-page read is still tR-bound: 60 us read >> ~10 us transfer
For one isolated page, tR wins and the cell still looks like the bottleneck. But SSDs do not read one page at a time. The controller pipelines: it issues a read to die 0, and while die 0 is busy in its tR window, the bus is free to drain a previously read page from die 1, then die 2, and so on. With enough dies interleaved on the channel, the tR latency hides entirely behind transfers — and the moment that happens, the channel is busy 100% of the time and the bus rate is the hard ceiling on throughput. The aggregate read bandwidth of the channel is no longer page_size / tR; it is simply the interface rate, full stop. This is exactly the regime modern drives operate in for sequential and high-queue-depth workloads.
So the bus rate matters enormously — and yet, as the previous section showed, you cannot raise the bus rate freely because the multi-drop load fights you, and you cannot pile on more dies-per-channel to hide tR better, because more dies lower the rate you can run. These two pressures collide. The resolution the industry has converged on is structural rather than electrical:
- Fewer dies per channel. Rather than 8 or 16 dies sharing a channel at a derated speed, put 2 or 4 dies on a channel and run it at full NV-DDR3 rate. Lighter load, cleaner eye, higher MT/s.
- More channels. Where a consumer controller once had 4 channels and an enterprise one 8, modern enterprise controllers field 16 or more independent channels, each a lightly loaded fast bus. Aggregate bandwidth is
channels x per_channel_rate, so you scale by widening, not by speeding a single overloaded bus. - Load-reduction tricks. Buffer or isolation devices that present a single small load to the controller and re-drive to a local cluster of dies (the flash analog of LRDIMMs) appear in patents and high-end designs, trading latency and cost for a recovered eye.
OLD: controller --[ heavily loaded bus ]-- 16 dies @ derated MT/s (few wide-but-slow channels)
NEW: controller --[ light bus ]-- 4 dies @ full MT/s x 16 channels (many fast channels)
--[ light bus ]-- 4 dies @ full MT/s
--[ light bus ]-- 4 dies @ full MT/s
... (aggregate = sum of channels)
The cost is obvious and unglamorous: more channels means more controller pins, more PCB routing layers, more PHY area and power, and a harder package. There is a real and growing fraction of SSD die area and power budget devoted to nothing but the I/O PHYs and their per-channel training logic. None of it stores a single bit. It exists solely to keep the eye open. This is the same dynamic that shapes the rest of the storage stack: the controller’s job is increasingly orchestration, as the flash translation layer decides which die to talk to and when, and error correction — see ECC for flash, Hamming to LDPC — cleans up what the channel and the cells get wrong.
Trade-offs worth naming honestly
It is tempting to read the MT/s table as pure progress, but each step bought speed with complexity and power. Async SDR needed no training, no termination, no calibration — it just worked, slowly, forever, with trivial controllers. Every generation since has added moving parts that can drift, mistrain, and fail. Read DQ/DQS training can and does fail in the field; controller datasheets document training-fail conditions, and a drive that mistrains a channel either retrains, derates, or errors. The calibration that opens the eye also takes time and power, has to be re-run as temperature and voltage drift, and adds latency to the cold path.
There is also a real tension between capacity and speed that marketing tends to paper over. The densest, cheapest configuration — many dies per channel — is the slowest per channel. The fastest configuration — few dies, many channels — costs more in controller and board. A QLC drive (the density endgame) optimized for dollars-per-terabyte will load its channels heavily and live with a derated bus; an enterprise drive optimized for throughput will do the opposite. Neither is wrong; they are different points on the same curve, and the interface is the axis that curve turns on.
And for all the cleverness, the wire is still the wire. ODT, differential strobes, DFE, per-pin Vref, and asymmetric DQS are increasingly elaborate ways of fighting capacitance and reflection on a shared bus — the same fight, escalated. At some point the multi-drop parallel bus runs out of headroom, which is part of why the industry keeps glancing at serial and packetized interfaces and at the architectures discussed in what comes after NAND. For now, NV-DDR3 and Toggle at 3600 MT/s, on lightly loaded channels, is the state of the art.
Verdict
The NAND interface spent two decades as an afterthought to the cell, and it is now the part of the stack that most directly bounds how fast an SSD can move data. ONFI and Toggle Mode are two brands of the same hard physics: a source-synchronous DDR bus that has climbed from 50 MT/s to 3600 MT/s only by adopting differential strobes, on-die termination, per-pin Vref and deskew training, duty-cycle correction, and equalization — an entire signal-integrity discipline imported wholesale from DRAM. The decisive constraint is the multi-drop topology. Hanging 16 dies off a shared bus buys capacity but loads the line with capacitance and reflections that throttle the achievable rate, while pipelining tR across those dies is exactly what makes the bus the throughput ceiling in the first place. The resolution is architectural: fewer dies per channel, more channels, more PHY silicon that stores nothing and exists only to keep the data eye open. If you want to understand why a modern SSD has the throughput it does, do not start with the cell. Start with the wire, count the dies on it, and look at how many independent wires the controller can drive at once.
Sources
- ONFI Specifications (specs index)
- Open NAND Flash Interface Specification Revision 5.2, 27 February 2024 (PDF)
- Open NAND Flash Interface Specification Revision 5.1, 3 May 2022 (PDF)
- ONFI Announces Publication of 4.1 Standard, Extending Speed to 1200 MT/s
- Open NAND Flash Interface Working Group - Wikipedia
- Evolution History of NAND Flash Interfaces - StorageNewsletter
- NAND Flash 101: Flash Device Interfaces - Phison Blog
- Flash 101: The NAND Flash electrical interface - Embedded
- Samsung, Toshiba Seek Big Increase in NAND Flash Speeds - PCWorld
- Read DQDQS Training Fail - Microchip Online Docs
- Anatomy of a Solid-state Drive - ACM Queue
- Improving NAND Throughput with Two-Plane and Cache Operations - Macronix (PDF)
Comments