Доброго дня. Сегодня я хотел бы рассказать о DDR4 в контексте модулей памяти.
1) Чуть-чуть об авторе
Автор имеет опыт в коммерческой разработке печатных плат около двух лет. До начала этого пути занимался баловством с микроконтроллерами на самодельных платах. На текущий же момент можно перечислить два значимых успешных проекта: материнская плата на RK3588 (LPDDR4X-4266MT/s, HDMI2.1, PCIe2/3, Ethernet 2.5G, USB2/3, SATA3), модуль памяти UDIMM DDR4 3200 MT/s. Разумеется, было много прочих, но они не требовали глубокого понимания работы с согласованием сигналов по задержке, понимания импеданса. Стоит учитывать, что автор является самоучкой чуть более чем полностью, так как более опытных коллег попросту не было и нет. Опыт работы имеется только с российскими фабриками.
Разработка велась в Altium, какого-либо моделирования (Cadence/Ansys/иной софт) не проводилось. Однако, проекты полностью работоспособны, что является косвенным доказательством валидности моих эвристик.
Последний вводный абзац. Если будет интерес и потребность – планируется сделать еще одну статью о workflow при работе с DDR4 в Altium. Также есть что рассказать про LPDDR4, если будет таковой запрос. Если есть интерес к разработке печатных плат – по ссылке доступно мое «пособие», полностью свободное.
2) Группы сигналов DDR4
Для лучшего понимания стоит начать именно с групп сигналов. Есть две разных шины – адресно-командная (CA) и шина данных (DQ). Описание всех линий вышло громоздким, так что будет в конце статьи.
Адресно-командная шина состоит из: CK_t/c, CKE, CS, ODT, ACT, BG0/BG1, BA0/BA1, A0-A17, PAR, ALERT, RESET.
Стоит рассказать о некоторых моментах, связанных с определенными линиями:
A10, A12, A14, A15, A16 – комбинированные, являются и адресными, и командными (подробнее в описании всех линий).
CK_t/c, CKE, CS, ODT – рангозависимые линии, их в одной шине два набора. Для первого ранга используются линии с цифрой «0», для второго – «1». Если на модуле ранг только один – неиспользуемую диффпару CK1_t/c необходимо подключить к резистору 75 Ом рядом с краевым разъемом (_t на один конец резистора, _c на другой). Все остальные линии (CKE1, CS1, ODT1) можно просто ни к чему не подключать.
Alert – нуждается в подтягивающем резисторе к VDD (порядка 40 Ом), который устанавливается со стороны первого (то есть, самого левого) чипа. Сама же линия ведется от краевого коннектора через последний (самый правый) к первому, в обратной всей CA-шине последовательности. НЕ нуждается в согласовании с остальной шиной, однако соблюдение импеданса и опорной плоскости требуется.
Reset – подтягивающий резистор не нужен, согласование не требуется, вести можно хоть совместно с CA-шиной, хоть противоположно ей. Импеданс и опорная плоскость – актуальны.
Шина данных состоит из: DQ, DQS_t/c, DM.
С этой шиной все проще, стоит лишь упомянуть рекомендацию по установке последовательного резистора около 15 Ом рядом с краевым разъемом на каждой линии (DQ, DQS, DM). Эти резисторы помогают не так сильно закидывать линии между процессором и слотом отражениями.
Питания. Это, конечно, не сигналы, но стоит кратко проговорить какие есть и зачем нужны:
· VDD – основное напряжение питания логики DRAM. Обычно – 1.2 Вольта.
· VDDQ – то же самое, что и VDD, но для домена DQ, часто объединяется в одну линию.
· VPP – напряжение, позволяющее управлять затворами ячеек памяти (а транзистор открывается при каждом взаимодействии с ячейкой, чтение/запись/refresh). Обычно – 2.5 Вольта.
· VREFCA – референсное напряжение для работы блока адреса и команд (CA и служебные сигналы). Обычно – 0.6 Вольта (VDDQ/2).
· VTT – терминационное напряжение, используется для внешнего согласования интерфейсных выводов (адресно-командной шины). Обычно – 0.6 Вольта (VDD/2).
3) Немного общих понятий
Для начала – виды чипов по «битности». Вы могли видеть цифры x4, x8 и x16 относительно чипов памяти. Это – количество линий данных на чип. Стандартная планка памяти имеет ширину шины данных в 64 бита. Посему логично, что чем меньше бит на чип – тем больше потребуется чипов. В случае со стандартными модулями классика – это х8, х16 используется несколько реже, х4 значительно реже. Получается, что в x4 чипах есть только 4 линии данных (+ диффпара DQS + DM/DBI), в x8 – то же самое, но 8 линий данных, а в х16 – два таких набора (то есть, 8 линий данных, DQS и DM/DBI – и так два раза в одном чипе). Если абстрагироваться от емкости чипов – то куда проще использовать x16 чипы, ибо их меньше – значит меньше точек подключения адресно-командной шины к чипам (чуть меньше ломается сигнал), больше расстояние между чипами (удобнее согласовывать, ибо больше места).
Ранее говорилось про «ранги» модуля памяти. Доводилось ли читателю видеть планки памяти, на которых чипы установлены с двух сторон? Ну вот это оно и есть (речь про обычные DIMM). То есть, на одних и тех же контактах шины данных может сидеть два чипа, и не запутывается контроллер памяти только благодаря рангозависимым линиям адресной линии (те же CS0/1, например). Зачем это надо? Увеличение максимального объема планки, в основном. Но трассировка становится труднее – ибо учитывать приходится уже два чипа на одной и той же линии, а не один.
Стоит понять, что такое fly-by и point-to-point. Это – тип подключения Master устройства к другим микросхемам. Point-to-point – подключение от точки к точке. Проще всего привести примеры – это PCIe, UART и так далее, то есть, соединение только между двумя микросхемами (или микросхемой и коннектором). Fly-by же соединяет Master с несколькими микросхемами, подключаясь каждой из своих линий к каждой микросхеме последовательно. Пример – тот же I2C или SPI.
А в DDR4 есть оба вида подключения, для линий данных – point-to-point, от процессора до слота, от слота до чипа памяти. Один источник, один адресат (линии двунаправленные, но не суть). Адресно-командная шина, в свою очередь, относится к fly-by, проходя от слота всеми линиями сначала до первого чипа, от него ко второму и так далее до последнего, после чего эти линии идут на «хвостовую терминацию». В итоге линии данных получаются довольно короткими и согласуются относительно просто (в случае однорангового модуля уж точно), но адресно-командные линии проходят через всю длину планки, и при их согласовании уже возникают трудности.
4) Практические рекомендации
Начнем с p2p-шины, то есть, шины данных. Как и было сказано, для всех линий на ней требуется установка резисторов по 15 Ом рядом со слотом (в случае с планкой). Ставить можно одиночные, сдвоенные (0404) или счетверенные (0408) резисторы, но важно помнить о том, что посадочное место у последнего варианта не очень равномерное (крайние контакты толще внутренних), из-за чего он не очень хорошо подходит для DQS (может дать перекос по задержке, что для дифференциальной пары хуже, чем для одиночных линий в шине).

Линия до резистора и после нее – считается одной и той же, а значит и согласовывать нужно эти линии целиком. Чтобы xSignals (инструмент Altium Designer) считал общую задержку на всей протяженности можно применить один «костыльный» метод: в схеме назначить одинаковую сетку на оба конца резистора, и закоротить эти резисторы на плате (просто нарисовать прямые линии одинаковой ширины под каждым). И теперь можно спокойно создавать класс xSignals от краевого слота до чипа памяти и видеть суммарную задержку линии. И да, крайне важно не забыть об этом, чтобы перед завершением проекта убрать эти перемычки в плате и схеме (или сделать копию проекта с пометкой final, чтобы сохранились данные по задержкам).
Теперь к fly-by шине, то есть, адресно-командной. Критически важно, чтобы все сигналы одной шины от источника доходили до чипа единовременно, и так с каждым чипом. То есть, задержка на каждом участке должна быть одинаковой. Участков тут несколько: процессор – краевой слот, краевой слот – первый чип памяти, первый чип – второй чип, <…>, последний чип – терминационные резисторы.
Настроить это довольно просто. Для каждого чипа придется повторить одинаковый алгоритм действий: xSignals Wizard, первым компонентом нужно выбрать краевой слот, вторым – первый чип памяти. Сетки –все, что указано в списке контактов адресно-командной шины (кроме alert и reset, их согласовывать по задержке нет нужды). Кстати, в случае с двухранговым модулем классов будет в 2 раза больше, так чип снизу – другой компонент, да и часть сеток там другая – CK, CS, CKE, ODT – рангозависимые. Следом – настройка правила High Speed (переход в задержки, указание допуска и целевой линии). И вот, можно проводить линии и согласовывать участок между слотом и чипом памяти.
Но тут есть маленькая ловушка. Задержку до каждого чипа нужно согласовать. Но что именно учитывать? Например, от общей шины отходят переходные отверстия до каждого чипа – надо ли их учитывать для последующих? И тут на выручку приходит…xSignals. Он полезнее, чем может показаться, ибо в расчете задержек в окне PCB – xSignals участвуют только те элементы топологии, через которые сигнал идет от конкретного компонента до конкретного компонента. То есть, для последующих чипов памяти учитываться fanout (дорожки на внешних слоях около BGA-микросхем и переходные отверстия для них) от предыдущих не будут, и это – правильно, так как для трассы они являются stub’ом, а не последовательной задержкой. Поэтому для последующих чипов необходимо настраивать классы xSignals так же от слота до чипа, и никак иначе.

Даже в случае с последним участком – от последнего чипа до терминационных резисторов нужно выбрать источником слот, а конечным компонентом…резисторы? Да, тут проблема, xSignals плохо работает с множественными компонентами. Поэтому можно создать библиотечный PCB-элемент, что будет состоять из этих резисторов. Да, снова «костыли», может есть решение изящнее, но оно работает. Для этого достаточно скопировать все эти резисторы разом, вставить в библиотеку pcblib, создать элемент. Если есть желание – можно собрать и УГО, чтобы подключить к правильным сеткам. Если нет – можно подключить сетки вручную. И вот этот «элемент» уже можно указывать конечным при настройке класса xSignals. Только рекомендуется не ставить его поверх настоящих резисторов хвостовой терминации, ибо иногда Altium отказывается адекватно считать задержку (почему – вопрос хороший). Тут, как и с закорачиванием резисторов на линиях данных, главное не забыть потом вернуть все на место. Еще один момент – номиналы этих резисторов. 39-50 Ом, подключать вторым концом к VTT. Для CLK между VTT и резисторами нужен конденсатор (да, для обеих линий – один, так как вторые концы резисторов терминации CLK соединяются). А вообще – лучше поискать схему, у Altium есть встроенные примеры и там лежит проект SO-DIMM планки, многие моменты подходят.
Немного про задержку в микросхемах. Если разрабатывается распаянная на материнской плате память – то процессор / контроллер / ПЛИС / что-то еще учитывать в общей задержке линий обязательно. Сами же чипы памяти – в целом, игнорировать можно, если читатель согласен снизить потенциальный бюджет на 3-5 пикосекунд из-за разброса (а обычно примерно такой разбег там и встречается). Но лучше попытаться добыть документацию от производителя, если это возможно.
5) Конкретные цифры и буквы
Теперь конкретные данные. Сначала – немного удивления. Шина данных –адекватная, опорой для нее является земля. А вот адресно-командная шина…она особенная, ведь опорой для нее является питание VDD. Это не автор придумал, так написано в официальной документации JEDEC (DDR4 SDRAM UDIMM Design Specification, JEDEC Standard No. 21C). Поэтому по обе стороны (по слоям) от шины данных крайне рекомендуется располагать цельные полигоны земли, а от линий адресно-командной шины – VDD.
Требования к импедансу. Одиночные линии – 40-55 Ом, дифференциальные пары – 70-93 Ом (допуск выглядит слишком большим, но все из того же документа JEDEC). Задержка…удачи, общих истинных значений нет. Intel пишет одно, AMD – другое, иные производители – третье и так далее. Поэтому лучше держать в голове допуск в 10 пикосекунд для шины данных и 20 пикосекунд для адресно-командной шины. Миллиметров тут не будет, почему – рассказано в предыдущей статье. На самом деле допуски по задержкам зависят от планируемой рабочей частоты. Эти вот приведены для скорости 3200 Мбит/сек, в ином случае может быть больше/меньше.
6) Описание всех линий DDR4
В адресно-командную шину входят следующие линии:
· CK_t/CK_c. Это дифференциальная пара (_t = P, c = _N), является линией синхронизации для адресно-командной шины. Обычно их две – CK0 и CK1 – используются для двух рангов.
· CKE – сигнал, управляющий состоянием памяти. 1 – нормальное функционирование, 0 – игнорирование команд, Power-Down или SelfRefresh. Есть CKE0 и CKE1 для двух рангов.
· CS – сигнал chip select, чип игнорирует все при CS = 1. Используется для выбора рангов в многоранговых системах, CS0 активирует нулевой ранг, CS1 первый.
· ODT – сигнал, включающий или выключающий On-Die-Termination для линий данных (сигналов DQ, DQS, DM). Тут снова есть ODT0/1
· ACT – сигнал активации команды (команды задаются через RAS/CAS/WE). При одном состоянии ACT контакты A16, A15 и A14 воспринимаются как адресные. При другом – эти контакты принимают сигналы RAS/CAS/WE соответственно.
· BG0/BG1– Bank Group, часть системы адресации чипа памяти (чипы обычно имеют 4 группы банков), по сути – «старшие биты» адреса.
· BA0/BA1 – контакты, отвечающие за адресацию к банку внутри группы банков, «промежуточный» элемент адреса между группой банков и адресом ячеек.
· A0-A17 – адресные контакты для доступа к ячейкам внутри банка памяти. Контакт А17 не нужен в случаях, когда емкость чипа меньше 4ГБайт. Некоторые контакты (А10-12, А14-16) мультиплексированы с дополнительными функциями, так что их необходимо подключать вне зависимости от объема чипа.
· RAS/A16 – комбинированный контакт, в зависимости от состояния ACT является адресным A16 (при 0) или командным (при 1). RAS (Row Adress Strobe) является одним из трех командных контактов этой группы (RAS, CAS, WE).
· CAS/A15 – комбинированный контакт, в зависимости от состояния ACT является адресным A15 (при 0) или командным (при 1). CAS (Column Adress Strobe) является одним из трех командных контактов этой группы (RAS, CAS, WE).
· WE/A14 – комбинированный контакт, в зависимости от состояния ACT является адресным A14 (при 0) или командным (при 1). WE (Write Enable) является одним из трех командных контактов этой группы (RAS, CAS, WE).
· BC/A12 – Burst Chop – функция, позволяющая управлять количеством тактов передаваемых данных. Стандартная длина – 8 тактов (речь именно о временной шкале, ширина канала управляется иначе). Если BC = 1, то последовательность данных режется до 4 тактов. При 0 длина остается стандартной – 8.
· AP/A10 – Auto-Precharge – переключение «предзаряда» на используемом банке или на всех банках чипа. При AP = 1 предзаряд идет на всех банках, при 0 – только на выбранном (на всех нужно в основном для refresh).
· PAR – однобитный Parity сигнал, проверка на четность для адреса/команд, эдакая примитивная CRC.
· ALERT – многофункциональный контакт, но в UDIMM почти всегда несет только две функции. Первая – проверка CRC данных (по DQ после burst – обычно 8 тактов – контроллер памяти шлет контрольную сумму отправленных данных). Вторая функция – сигнализация о несовпадении Parity по командам/адресу.
· Reset – классический reset, активен при 0, в стандартном состоянии должен быть 1 для адекватного функционирования чипа. Подтяжка не требуется. НЕ требует согласования с остальной шиной, но импеданс и возвратный путь – надо.
Теперь – про шину данных:
· DQ0-7– контакты двунаправленной шины данных. Нуждается в последовательном резисторе рядом с контактными площадками самой планки (около 15 Ом). Можно менять линии местами внутри младшей и старшей половин байта (DQ0-3 и DQ4-7) одного чипа, но не между этими половинами.
· DQS_t/DQS_c – отдельный тактовый сигнал (строб) для линий данных. Является дифференциальной парой, уникален для каждого байта (в х16 конфигурации есть DQSL и DQSH для младшего и старшего байтов), следовательно, линии DQ согласуются с длиной/задержкой именно этого сигнала. Последовательные резисторы по 15 Ом так же востребованы.
· DM/DBI/TDQS_t – содержит несколько функций. DM – Data Mask – при 1 данные на конкретном байте не будут записаны в память, DQ игнорируются. При 0 все пишется как обычно. DBI – Data Bus Inversion – используется для экономии энергии при передаче сигналов (например, если в байте единиц больше половины – DBI устанавливается в 1, передаваемые данные инвертируются). TDQS – НЕ используется в UDIMM от слова совсем. Последовательный резистор на 15 Ом тоже нужен.
· TDQS_c – TDQS – НЕ используется в UDIMM от слова совсем, поэтому TDQS_c игнорируется и не подключается.
Комментарии (7)

nerudo
24.04.2026 18:14Скажите, если на двухранговых модулях чипы паяются с двух сторон печатной платы, то на 4-ранговых как, с 4 сторон?

Mirakuru77 Автор
24.04.2026 18:144 ранга в стандартном декстопном сегменте в контексте DDR4 не может быть, это строго серверные RDIMM и так далее. На стандартном коннекторе DIMM есть контакты только под два ранга.
За DDR4 RDIMM или DDR5 говорить не могу, так как не занимался изучением этих интерфейсов и не работал с ними.
Пояснение про 2 стороны было преведено чисто с обывательской точки зрения, так проще понять о чем идет речь.

StpMA
24.04.2026 18:14Почему конденсаторы для VTT на модуле памяти ставятся между VTT и VDD ? Почему не между VTT и GND? Посмотрел несколько примеров модулей. Там один сплошной слой VDD, а GND собирают из кусочков. Получается для CMD/ADDR опорный слой VDD. Но, допустим, у меня собственная плата (не DIMM) на которой стоит и контроллер и память. Много сплошных слоев GND и один VDD. Опорный слой для всех сигналов GND. Не лучше и проще подключать конденсаторы между VTT и GND ?
Аналогичный вопрос про CK_t/CK_c .
NickDoom
Что ж вы, люди, творите. Вы ж можете вместе мир перевернуть…
Интересно, кстати, реалистична ли моя мечта — «видеокарта-утилизатор» для кучи мелких DDR (сейчас уже это будет DDR4, конечно). Ящик или ноут апнули, мелкую планку вынули, добавили в видеокарту. А там какие-нибудь дешманские GPU, которые умеют с ней работать, но их очень много и у каждого — один десктопный слот памяти и два бучных :)
Я про аппаратную сторону вопроса. То, что на уровне драйвера это всё заставить работать и балансировать нагрузку — «задачка-неберучка», я не буду спрашивать :)
Mirakuru77 Автор
Теоретически - возможно, если найдется чип GPU совместимый с DDR4. На практике, увы, есть два затыка: стоимость платы в малой серии будет порядочной. И главное - документация на GPU, достать ее будет трудно.
0xdead926e
емнип у нвидии последними совместимыми с ддр4 были паскали. но там уже нельзя редактировать прошивку, поэтому облом.
p0isk
Была похожая идея для битых планок памяти, которые вообще ничего не стоят. Создаётся материнка с 8-16-32 слотами под них. В качестве контроллера плис, интерфейс общения usb/sata/pci-e. Контроллер точно так же, как и в жёстких дисках хранит информацию о битых адресах и перенаправляет запись в резевную область. Цель - быстрый относительно накопителей и дешёвый относительно озу кэш.