The Jerusalem PostYemeni forces withdraw from Bab el-Mandeb Strait, leaving Iran-backed Houthis in controlPunchFULL LIST: Teams leading AFCON 2027 qualifying groupsInquirer EntertainmentActress-politician faces license suspension from LTO after dancing while drivingInquirerRomualdez’s congressional aid continues despite suspension – AcidreSky TG24Perù, Papa Leone XIV a Zaña: appello contro la criminalitàCNN TürkKörfez yine alarmda! İran'dan ABD'ye misilleme: Bahreyn’deki üssü 6 İHA ile hedef aldı…Daily MaverickThe baboons are doomed, and welfare groups just missed the last chance to save themCapital FMIndia and UAE deepen energy ties with proposed strategic oil storage dealColliderJulia Roberts’ $205M Romance Hit Is Officially a Global Streaming Sensation3DNewsКитайская Bilibili Gaming cтала чемпионом World Championship 2026 по League of Legends, прервав многолетнее доминирование корейских командZDF heuteEntdecken Sie das ZDF-NachrichtenstudioIl Fatto QuotidianoYouTube blocca 16 canali russi in Ucraina: stop anche per Masha e Orso, considerato “strumento di propaganda del Cremlino”
The Daily Newsstand · Free, Always
Sunday, November 15, 2026

Школьный проект немного разросся: разрабатываем карманный мультитул электронщика на ПЛИС

Translate
Мы и наш стенд на Тыкворкинг’26 в МЭИ

Слева направо: Ярик, наш стенд на Тыкворкинг’26 в МЭИ и Ромка

❯ 0. Вступление

Привет, Хабр! Я Рома Горбачев, учусь в десятом классе и делаю Fabbit — открытый карманный мультитул электронщика на ПЛИС вместе с другом Яриком Павлюком. Этакий Flipper One, да не для сетей и вайфаев, а для низкоуровневой работы с платами, проводами и протоколами.

Задумка простая: выбираешь в меню нужный инструмент — микроконтроллер-супервизор прямо на ходу загружает в ПЛИС другой битстрим, и за полсекунды внутри кристалла меняется сама цифровая схема. Не запускается другая программа на том же процессоре, а на лету пересобирается аппаратная начинка! В одну коробочку я заложил 24-канальный логический анализатор, двухканальный осциллограф (2x400 MS/s) с генератором сигналов, лабораторный блок питания (0,8–22 В, до 20 Вт) со сквозным ваттметром (0,2 мкА…3 А) и аппаратным глитчером, мультиметр, отладчик с трассировкой (Debug & Trace) и аппаратную ретроконсоль. Да, в Марио и Сегу между дебагом тоже хочется!)

Рендер будущего устройства

Рендер будущего устройства

Полный список того, что заложено в целевую плату (ТТХ и начинка)
  • Двухканальный осциллограф: 8-битный АЦП HMCAD1511, 2x312–375 MS/s штатно и 2x400 MS/s после подстройки задержек LVDS. Входной тракт 1 МОм с бистабильными реле (делители 1:1/1:10, открытый и закрытый вход), JFET-буферами и щупами x1/x10.

  • Лабораторный блок питания и сквозной ваттметр: выход 0,8–22 В с шагом 10 мВ и ограничением тока (CV/CC). Отдаёт до 20 Вт от зарядника USB-C PD 3.1 и до 5 Вт от аккумулятора. Считает напряжение, ток, мощность и энергию (20-битный монитор INA228), а при выходе до 5,5 В меряет ток с автодиапазоном 0,2 мкА…3 А — видно и сон микроконтроллера, и пики радиопередатчика. Быстрый усилитель тока INA241 (1,1 МГц) заведён на АЦП ПЛИС, чтобы смотреть форму бросков тока во времени.

  • Аппаратный глитчер (Fault Injection): силовой ключ («лом»), который по тактам ПЛИС коротит питание цели на землю (расчётный фронт 15–20 нс) для атак сбоем питания.

  • Логический анализатор на 24 канала: Порт A — 16 входов 0–10 В (целевая стойкость защиты ±30 В, порог компараторов TLV3501 задаётся в диапазоне 0–6,8 В, отдельные входы CK и TRIG). Порт B — 8 двунаправленных линий с перестраиваемыми уровнями 1,1–4,7 В. Буферный захват до 400 MS/s во внутреннюю память ПЛИС и непрерывный поток в ПК по USB 3.0 (50 MS/s на 16 каналах или 100 MS/s на 8) напрямую в PulseView / sigrok.

  • Генератор сигналов (DDS / AWG): 14-битный ЦАП DAC904 (165 MS/s) с выходным каскадом OPA2673. Выдаёт 9,6 Впп без нагрузки и 4,8 Впп на 50 Ом (требование к защите выхода — встречные ±25 В). На спинке прибора стоят три разъёма SMA (CH1, CH2, GEN) — генератор и оба канала осциллографа работают одновременно, так что АЧХ фильтра (диаграмму Боде) можно снять за один проход.

  • Мультиметр (DMM): 24-битный АЦП ADS1220 со встроенными источниками тока — напряжение, сопротивление, прозвонка и проверка диодов.

  • Отладчик Debug & Trace: разъём MIPI-20, CMSIS-DAP v2 (SWD, JTAG) и 4-битный параллельный вход трассировки (trace) для OpenOCD, pyOCD, probe-rs и orbuculum.

  • Ретроконсоль: аппаратные ядра NES, Sega Mega Drive и SNES на встроенном 3,5-дюймовом IPS-экране (640x480) и полноразмерном HDMI.

  • Сменный мезонин и начинка: модуль ПЛИС Colorlight i9+ в разъёме SO-DIMM (Artix-7 XC7A50T: 32 600 LUT6, 2,7 Мбит BRAM, 120 DSP, 8 МБ SDRAM x32, 16 МБ флеш), постоянно живущий супервизор WCH CH32H417 (двухъядерный RISC-V до 400 МГц, 896 КБ ОЗУ, USB 3.0 5 Гбит/с и 16-битная параллельная шина UHSIF к ПЛИС), ESP32-C5 (Wi-Fi 6 на 2,4 и 5 ГГц, BLE 5, 802.15.4), опорный генератор TCXO 25 МГц ±0,5 ppm (шкала времени и частотомер), сменная плата-мезонин на разъёме BergStak 2x40 (35 линий ПЛИС под сменные модули расширения), ИК приём и передача, IMU, динамик 1 Вт, микрофон, линейный вибромотор LRA, Qwiic, аккумулятор Li-pol 2800 мА·ч и MCP-сервер для управления прибором через ИИ-агентов.

Звучит как заявка на грант от самого себя. Поэтому сразу скажу как есть: карманного прибора в корпусе пока нет. Собственную шестислойную плату под CH32H417 я сейчас черчу — схема в работе. Зато у меня на столе живёт и работает стенд: модуль Colorlight i9+ с Artix-7 на отладочной плате, рядом ESP32-S3, самодельный джойстик на 11 кнопок, пучок дюпонтов и HDMI-монитор.

Стенд сегодня: модуль Artix-7 в сокете SO-DIMM справа, временный супервизор ESP32-S3 на макетке и макароны из проводов

Стенд сегодня: модуль Artix-7 в сокете SO-DIMM справа, временный супервизор ESP32-S3 на макетке и макароны из проводов

На стенде уже работают меню, подгрузка профилей микроконтроллером в ПЛИС прямо на ходу (горячее переключение из кэша за 0,6 с и аварийный возврат обратно), аппаратные Денди (NES) и Sega Mega Drive на 12 игр, а также буферный логический анализатор на 16 каналов с номинальными 400 MS/s, просмотром осциллограмм на мониторе и выгрузкой в PulseView. А 30 октября стенд прошёл первое боевое крещение на публике: я выступил с докладом про Fabbit на конференции пет-проектов Тыкворкинг’26 в МЭИ, там же развернул демо на нетворкинге (КДПВ как раз оттуда!) и все желающие рубились на живой ПЛИС в Mario, Sonic 3, Road Rash 3 и Ultimate Mortal Kombat 3. Исходники открыты на GitHub (код под MIT, железо под CERN-OHL-S-2.0).

Под катом: как я четыре раза перевыбирал архитектуру, как мы с Артёмом Кашкановым расковыряли закрытый драйвер нового микроконтроллера в эмуляторах без самого чипа, почему кадр экрана влез в память, а тактовый сигнал не пролез на ножки, и как проверка логического анализатора на живых проводах привела к детективу с байтом 0xFC.

Фух, краткую версию рассказал, картинки показал — быстрый дофамин получен! Теперь поподробнее: как я вообще до этого докатился?

❯ 1. Вообще-то нам просто задали проект

В десятом классе нам нужно выполнить индивидуальный проект. Делать нечего — пошёл придумывать тему. Желание сразу одно: железки. До угара железок! И ПЛИСятин =) Опыта разработки сложных проектов у меня при этом не было, но воображению это ни капельки не мешало)

Пнул Ярика — лучшего друга и одноклассника: давай, мол, вместе, так веселее. Ярик взял на себя менеджмент и часть 3D-моделирования корпуса, а я засел за всю электронику, архитектуру, Verilog и прошивки; параллельно искал нам и проекту выход в «люди».

У электронщика на столе частенько зоопарк: логический анализатор, USB-UART, программатор, отдельный блок питания, мультиметр, а если повезёт, ещё и осциллограф. Каждый со своим проводом, своей программой и своим геморроем. Хочется одну коробочку, которая перестраивается под задачу. А раз перестраивается, то пусть уж и в Марио умеет — отдыхать же надо!)

Двадцатого сентября в репозитории появился первый коммит. В README тогда было ровно две честные строчки: «Кода нет, платы нет». Зато уже лежал набросок корпуса в Blender. Приоритеты, ага.

❯ 2. Что Fabbit должен уметь и как он устроен

Начнём с главного понятия. Профиль — это аппаратное назначение прибора: битстрим ПЛИС, данные к нему и поведение в меню. Когда ты выбираешь профиль, микроконтроллер-супервизор прямо на ходу заливает нужный образ в ПЛИС и переключает кристалл в новую схему. При этом одна карточка в меню может объединять несколько битстримов: для «Ретроконсоли» я решил держать по отдельному полному образу ПЛИС на каждую приставку, и микроконтроллер сам подменяет их на лету при выборе игры.

Один модуль ПЛИС — разные приборы. Сплошная рамка — уже работает на стенде, пунктир — заложено в целевую плату

Один модуль ПЛИС — разные приборы. Сплошной аутлайн — уже работает на стенде, пунктир — заложено в целевую плату

Сценарий, ради которого всё затевалось: подключаю щупы к отлаживаемой плате, подаю на неё питание с ограничением тока, смотрю потребление, тем же прибором останавливаю микроконтроллер через SWD, ловлю событие на шине SPI и смотрю дорожки на экране прибора или выгружаю в PulseView. Без пачки отдельных коробочек в рюкзаке.

Чтобы уместить всю начинку в корпус 90x150x22,5 мм (над аналоговым модулем 24 мм), я разложил главную плату на две стороны. Спереди стоят экран, кнопки и динамик; сзади под крышкой — модуль ПЛИС в сокете SO-DIMM, плоский аккумулятор 904070 и сменный модуль-мезонин на скоростном разъёме BergStak 2x40. Мезонин сделан съёмным специально ради модульности: на его разъём выведены 35 быстрых линий ПЛИС и питание, так что простой перестановкой платки мезонина в прибор можно добавлять совершенно новые аппаратные функции (штатно туда ставится модуль осциллографа, генератора и мультиметра, а при желании можно воткнуть свою плату под SDR, специфичные интерфейсы или автоэлектронику).

Зоны главной платы (84,4x145,6 мм): слева лицевая сторона F, справа сторона крышки B с модулем i9+, мезонином и батареей

Зоны главной платы (84,4x145,6 мм): слева лицевая сторона F, справа сторона крышки B с модулем i9+, мезонином и батареей. МК потерялся под батарейкой :(

Профиль

Что делает

Главное требование к платформе

Статус

Логический анализатор

захват 16 линий 0–10 В (A) и 8 линий 1,1–4,7 В (B)

быстрые входы, память, точный триггер, USB 3.0

на стенде 16x400 MS/s в буфер, с оговорками (глава 6)

Ретроконсоль

NES, Sega Mega Drive, позже SNES

память SDRAM x32, видео, ввод

NES и Mega Drive работают на стенде, SNES в симуляции и сборках

Демо-сигналы

меандры 10/100 кГц, ШИМ, UART, SPI с ESP

безопасные выводы и уровни

на стенде

Отладчик Debug & Trace

CMSIS-DAP v2: SWD/JTAG, trace 4 бит

двунаправленный порт, быстрый разворот, MIPI-20

в проекте целевой платы

Осциллограф, генератор, мультиметр

2x400 MS/s (HMCAD1511), ЦАП DAC904, DMM ADS1220

сменный модуль-мезонин (BergStak 2x40), 10 пар LVDS, 3xSMA

в проекте целевой платы (выбран BOM и механика)

Лабораторный БП и глитчер

0,8–22 В (до 20 Вт), ток 0,2 мкА…3 А, ключ «лом»

USB-C PD 3.1, двунаправленные ключи от 0 В

в проекте целевой платы (схема в работе)

❯ 3. Зачем тут ПЛИС и почему она не справится одна

Анализатору нужно смотреть на 16 входов сотни миллионов раз в секунду и сравнивать все биты с условием триггера одновременно. Ретроконсоли нужно потактово повторить железо старой приставки, где процессор, видеочип и звук работают параллельно. Осциллографу — принять поток с быстрого АЦП по дифференциальным парам LVDS. Микроконтроллер исполняет инструкции по очереди, а ПЛИС сама становится нужной цифровой схемой.

Но пока ПЛИС перезагружается в другой профиль, её логики не существует. Если меню, файлы и USB живут внутри неё, при каждой смене профиля прибор на секунду отваливается от компьютера и слепнет, а битый образ на карте памяти превращает его в кирпич.

Поэтому я разделил систему на две части: рядом с ПЛИС всегда работает микроконтроллер-супервизор. Он держит соединение по USB, читает microSD, управляет питанием, рисует меню, прямо на ходу заливает новые битстримы в ПЛИС (в кэш слотов флеша или с мгновенным переключением активного слота) и реанимирует систему после любого сбоя. А ПЛИС молотит быстрые параллельные потоки.

Распределение ролей: слева текущий стенд на ESP32-S3, справа целевая плата на CH32H417

Распределение ролей: слева текущий стенд на ESP32-S3, справа целевая плата на CH32H417

Код (отчасти), расчёты по даташитам и тесты я пишу вместе с ИИ-агентами: так быстрее, и это часть идеологии проекта — свои профили потом сможет собирать любой. Но решения, паяльник, провода и ответственность за то, что прошито во флеш, остаются на мне.

По бумагам все шикарно! Давайте к проверке реальностью.

❯ 4. Как менялась архитектура

4.1. Модуль ПЛИС: от Tang Nano до Artix-7 в разъёме памяти

Первым кандидатом был Tang Nano 20K: дешёвый, открытый тулчейн, много примеров. Но свободных ножек мало, а запаса по логике хотелось больше. Паять голый чип в каком-нибудь BGA-484 и разводить вокруг него память на своей первой плате — верный способ закопать себя с проектом.

Решение нашлось у китайских производителей контроллеров для светодиодных видеостен. Сначала мне приглянулся модуль Colorlight i9 на Lattice ECP5 — платка в стандартном ноутбучном разъёме SO-DIMM на 200 контактов, под который легко развести свою материнку. И почти сразу я увидел его старшего брата Colorlight i9+ с Xilinx Artix-7 XC7A50T (32 600 LUT6, 2,7 Мбит BRAM, 120 DSP, рядом SDRAM 8 МБ x32 и флеш 16 МБ) в том же форм-факторе всего за 2500 рублей на Али:

Лот Colorlight i9+ на AliExpress: Artix-7 XC7A50T с памятью и питанием по цене пары коробок пицц

Лот Colorlight i9+ на AliExpress: Artix-7 XC7A50T с памятью и питанием по цене пары коробок пицц

Первый заказ продавец отменил, сославшись на проблемную партию памяти (объяснение меня не убедило — товарищ явно путался в показаниях XD). Перезаказал у другого, заплатил неделей ожидания. На самом модуле, кстати, ещё стоят два гигабитных Ethernet PHY Broadcom — для карманного прибора они лишние, поэтому на стенде и в целевой плате я держу их общий пин сброса (шар H2) в нуле, экономя 25 мВт.

Готовой отладочной платы специально под i9+ я не нашёл, взял плату расширения от i5/i9. Нюанс вскрылся: у i9+ выводы JTAG (TCK, TMS, TDI, TDO) не выведены на разъём SO-DIMM, а сидят на четырёх сквозных площадках J2–J5 в углу модуля (у i9+ они находятся слева, а у i5/i9 — снизу). Припаялся, подключил — и 10 октября прочитался IDCODE 0x0362C093, а следом замигала первая мигалка:

10 октября: JTAG подпаян к площадкам J2–J5, в ПЛИС крутится первая мигалка

10 октября: JTAG подпаян к площадкам J2–J5, в ПЛИС крутится первая мигалка

4.2. Супервизор: ESP32-S3 → CH569W → CH32H417 и допрос блоба в эмуляторе

Начинал я со связки ESP32-S3 N16R8 (меню, SD-карта, питание и кнопки) плюс отдельный мост FT232H и USB-хаб GL850G для скоростного потока анализатора в ПК. Первые грабли прилетели из даташита модуля N16R8: линии GPIO33–37 внутри модуля заняты восьмибитной памятью Octal PSRAM. Из-за этого связь с ПЛИС пришлось урезать с 8 бит до 4-битного Quad SPI.

Потом откликнулся Артём Кашканов (@radiolok) и предложил добавить отладчик с трассировкой (Debug & Trace). Одной новой строчкой в меню это не закончилось. Во-первых, входы анализатора с делителями и компараторами умеют только слушать, а отладчику по SWD/JTAG нужно быстро разворачивать линию на передачу. Единый порт я разделил на два: Порт A для анализатора (16 входов 0–10 В, целевая защита ±30 В) и Порт B с восемью двунаправленными линиями 1,1–4,7 В, плюс разъём MIPI-20. Во-вторых, потоковой трассировке и 16-канальному ЛА понадобился быстрый канал в ПК — USB 3.0.

Артём посоветовал посмотреть на WCH CH569W: один чип со встроенным USB 3.0 и параллельной шиной HSPI выкидывал из схемы ESP32, FT232H и USB-хаб. Я почти переехал на него. Но при детальном разборе у CH569 обнаружилось всего 128 КБ ОЗУ, отсутствие АЦП и I²C (понадобились бы три расширителя портов и I²C-мультиплексор), дефицит GPIO, конфликт 16-битной шины с контроллером SD-карты и ноль штук на складе LCSC.

Мне требовался чип, который совмещает аппаратный USB 3.0 и быструю параллельную шину к ПЛИС с большой памятью и богатой периферией. Раскуривая документацию WCH и мучая Клода, я вышел на свежий двухъядерный CH32H417QEU6: 896 КБ ОЗУ, 95 GPIO, АЦП, четыре I²C, USB 3.0 SuperSpeed и 16-битная параллельная шина UHSIF к ПЛИС. Минусы тоже честные: молодой SDK, часть драйвера шины в закрытой библиотеке libUHSIF.a и корпус QFN-128 с шагом 0,35 мм (ой, ну и гемор будет ручками паять!).

Выбор супервизора: проверенный, но тесный CH569 против нового CH32H417

Выбор супервизора: проверенный, но тесный CH569 против нового CH32H417

Платы с H417 на руках тогда не было, а узнать, какие ножки в реальности захватывает закрытая библиотека libUHSIF.a, было необходимо до рисования схемы. Поэтому 17 октября я устроил блобу допрос без железа: написал на Python небольшой эмулятор RISC-V, скормил ему скомпилированный код инициализации и прогнал все 144 комбинации параметров UHSIF_GPIO_Init(), записывая каждое обращение к регистрам GPIO и мультиплексора выводов.

Так ещё до разводки платы я узнал точный список из 28 ножек шины под ПЛИС и поймал реальный конфликт: сам блоб чужие пины не трогает, а вот штатная функция SD_GPIO_Init() из открытой части SDK молча перетирает линии данных шины PC8/PC9 (для SD-карты напишу свою короткую инициализацию). Мы обсудили этот закрытый блоб с глубокоуважаемым Артёмом Кашкановым, и он решил помочь — буквально на следующий день нырнул в эту задачу в своём проекте rln-trace! Артём прогнал всю библиотеку под трассировкой в эмуляторе Spike/Unicorn, раскопал внутри таблиц настройки настоящий «микрокод» конечного автомата диаграмм (очень похожий на GPIF II из Cypress FX3, который приходится вытаскивать из блоба как есть) и написал открытый драйвер fw/uhsif — он собирается обычным GCC без кастомных инструкций WCH и в CI до единого обращения к регистрам сверяется с оригинальной библиотекой!

Технические подробности допроса libUHSIF.a (XW, HPE, DWARF, микрокод и адреса регистров)
  1. Слинковал libUHSIF.a штатным компилятором xPack GCC 15.2 и разобрал дизассемблером. Внутри нашлись 14 проприетарных 16-битных инструкций расширения XW (c.lbu/c.sb — сжатые байтовые загрузки/сохранения WCH) и требование включать аппаратный стек прерываний HPE.

  2. Мой питоновский эмулятор (emu.py + runall.py) исполняет код инициализации по дизассемблированному ELF-файлу и перехватывает все обращения к периферии выше 0x40000000 (GPIO, тактирование и AFIO): прогон всех 144 комбинаций подтвердил, что спорные выводы PF12, PF13, PE7, PE11, PE15 библиотека не трогает ни в одном из режимов.

  3. Из отладочной информации DWARF и трассы эмулятора я вытащил карту 76 регистров UHSIF (0x40038000–0x4003812C): их имена и смещения совпали с регистровой картой GPIF II из Cypress FX3.

  4. Когда мы обсудили эту находку с Артёмом, он в rln-trace/doc/ch32h417-uhsif.md разобрал работу DMA-сокетов (0x40039000), двух банков программы конечного автомата (0x4003A000 / 0x4003B000) и поднял открытый C-драйвер с автоматической проверкой эквивалентности трасс в эмуляторе (12 сценариев, ~12 тыс. обращений). Поведение на реальном кремнии под потоком DMA проверим, когда приедет плата.

Вот тут вопрос к вам. CH569W: проверенный многими проектами, но тесный, часть функций пришлось бы выносить на дополнительные корпуса. CH32H417: всё в одном кристалле с 896 КБ памяти, но свежий, с закрытым кусочком драйвера и шагом выводов 0,35 мм. Бюджет околонулевой, плата ручной сборки, ошибка в выборе стоит месяца. Что выбрали бы вы?

Я выбрал H417, оставив CH569 запасным вариантом. Девборду с ним нам заказал Артём. А стенд на ESP32-S3 никуда не делся: на нём живёт всё, что вы увидите в пятой и шестой главах.

4.3. Экран: кадр в память влезает, а pixel clock — нет

Мне очень хотелось, чтобы в меню ПЛИС спала выключенной, а экран вёл микроконтроллер: экономия батареи и красивая архитектура. У H417 есть встроенный контроллер дисплея (LTDC), а банки памяти DTCM (256 КиБ) и основная SRAM (512 КиБ) идут в адресном пространстве подряд — так что полный кадр 640x480 в RGB565 (600 КиБ) целиком помещается в ОЗУ. Казалось бы, готово!

Но потом начинаешь раскладывать альтернативные функции ножек… У LTDC ровно четыре возможных вывода тактового сигнала пикселей LTDC_CLK: PF1, PB14, PE14, PA15. При включённой 16-битной шине UHSIF, SD-карте и USB заняты все четыре (DATA7, CS#, WRNF, DATA15), да ещё и конфликтуют линии цвета G4 и B6:

Можно было бы урезать шину к ПЛИС с 16 до 8 бит, но тогда вдвое падает пропускная способность анализатора. Ножек 95, а нужной функции не хватает одной!

Тогда я посчитал в Vivado и померил на живом модуле тестовый образ «монитора меню» без умножителя частоты MMCM (развёртка и SDRAM напрямую от генератора 25 МГц): сколько вообще съедает ПЛИС в таком режиме? Оказалось — 0,56 Вт на весь модуль. За пару минут, которые пользователь проводит в меню за сессию, это около 0,2 % ёмкости батареи.

Решение: экран всегда подключён к ПЛИС. Микроконтроллер рисует меню в свой буфер (я написал лёгкий UI-движок на C11: 4 бита на пиксель, 150 КиБ на кадр, пересылка только изменённых прямоугольников dirty rectangles), ПЛИС выводит картинку на IPS-экран и HDMI, а когда МК на ходу подгружает в ПЛИС боевой профиль, экраном без задержек начинает владеть уже сама схема профиля.

4.4. Лабораторный источник и глитчер: один тракт для трёх задач

В проекте целевой платы от силовых пинов питания (P1 и P2 на верхнем торце) я заложил сразу три режима:

  1. Выдавать регулируемые 0,8–22 В с ограничением тока (преобразователь TPS55289) и мерить потребление.

  2. Работать сквозным измерителем: когда внутренний БП выключен, на P1 подаётся внешнее питание до 20 В / 3 А, с P2 уходит в нагрузку, а шунт посередине считает ток, мощность и энергию.

  3. Работать глитчером: по команде ПЛИС коротить выход P2 на землю на десятки наносекунд.

Первый вариант схемы с электронным предохранителем TPS25947 отпал ещё при сверке даташита: он не работает ниже 2,7 В (а мне нужно от 0,8 В!) и запирает обратный ток. Тогда я разделил коммутацию и ударный ключ:

Схема силового тракта в проекте платы: фотовольтаические ключи S1–S3 работают от 0 В в обе стороны, а быстрый MOSFET AO3400A («лом») коротит выход P2

Схема силового тракта в проекте платы: фотовольтаические ключи S1–S3 работают от 0 В в обе стороны, а быстрый MOSFET AO3400A («лом») коротит выход P2

Направление тока переключают встречно-включённые N-MOSFET PXN012-60QL под управлением фотовольтаических оптодрайверов VOM1271 — они держат от 0 до 20 В в обе стороны, но открываются за 1,3–3,2 мс. А прямо на выходе P2 стоит отдельный скоростной ключ AO3400A с драйвером UCC27517: когда нужен сбой питания, ПЛИС бьёт в его затвор (расчётный фронт просадки — 15–20 нс!).

4.5. Аналоговый мезонин: модульность, 1 МОм и сопромат крышки

Аналоговую часть (быстрый АЦП HMCAD1511, ЦАП DAC904, точный ADS1220, реле, делители) я сначала хотел держать на отдельном мезонине, потом перенёс на основную плату ради коротких LVDS-связей, а затем вернул обратно на сменный модуль. Довод «LVDS через межплатный разъём не пройдёт» не подтвердился (разъём BergStak 0,8 мм держит до 12 Гбит/с!). Зато тащить через разъём высокоомную точку 1 МОм после входного делителя было бы фатальной ошибкой из-за утечек и наводок.

И главное — сменный мезонин даёт прибору настоящую аппаратную модульность. На 80-контактный разъём выведены 35 линий ПЛИС (включая дифференциальные пары LVDS) и питание: вынимаешь аналоговый мезонин с осциллографом и ставишь на его место другую платку под новую задачу, вообще не переделывая шестислойную материнку. А под капотом самого мезонина стоит собственная EEPROM с описанием модуля, чтобы супервизор при включении сразу понимал, какое железо сейчас пристёгнуто, и предлагал нужные профили ПЛИС.

На спинке модуля встали три разъёма SMA (на BNC в карманном корпусе места нет). Расплатились задней крышкой: когда мезонин вырос до 73x37,3 мм, верхний край крышки повис в воздухе, и в прочностном расчёте (CalculiX FEM во FreeCAD, нагрузка 50 Н) пластик прогнулся на 1,24 мм прямо до деталей. Простое утолщение стенки не спасало, а вот замковое соединение шип-паз, опёртое на поясок корпуса, снизило расчётный прогиб спинки до 0,19–0,20 мм при безопасном зазоре 0,4 мм!

Шесть недель разработки на одной шкале :)

Шесть недель разработки на одной шкале :)

К этому моменту выбирать платформу я уже немного научился. Хотелось бы теперь ещё перестать… её перевыбирать.

❯ 5. Что я уже сделал на стенде

Возвращаемся с небес к макетке на столе.

Живой стенд: 11-кнопочный true handmade джойстик спереди, ESP32-S3 на бредборде и модуль Artix-7 на девборде

Живой стенд: 11-кнопочный true handmade джойстик спереди, ESP32-S3 на бредборде и модуль Artix-7 на девборде

Схема стенда: QSPI на гребёнке P3, входы анализатора на P2 и генератор петли самопроверки на P6

Схема стенда: QSPI на гребёнке P3, входы анализатора на P2 и генератор петли самопроверки на P6

Меню → загрузка битстрима на ходу → возврат

Как работает смена прибора на лету? Включаем питание: с нулевого адреса 16-мегабайтной флешки ПЛИС стартует аппаратно защищённый от стирания образ golden, микроконтроллер ESP32-S3 рисует меню (640x480, 4 бита на пиксель), а ПЛИС выводит его на HDMI.

Дальше ты выбираешь в меню нужный прибор или игру — и микроконтроллер прямо на ходу заливает и переключает битстрим в ПЛИС: сверяет CRC образа в кэше из пяти слотов флеша, если такого профиля в кэше ещё нет — тут же по шине QSPI дописывает .fbp-образ в свободный слот и подаёт команду IPROG. ПЛИС через внутренний блок ICAPE2 за доли секунды пересобирает свою логику из указанного слота, а при выходе из профиля (или если образ вдруг оказался битым и сработал сторожевой таймер) так же на лету возвращается обратно в golden-меню!

Карта 16-мегабайтного флеша ПЛИС (MX25L12833F)
0x000000  golden, 4 МиБ, защищён аппаратно битами BP=7, TB=1
0x400000  слот 0 ┐
0x640000  слот 1 │
0x880000  слот 2 ├─ кэш на 5 слотов по 0x240000 = 2,25 МиБ
0xAC0000  слот 3 │
0xD00000  слот 4 ┘
0xFF0000  таблица слотов "FBST" (CRC32, длина, счётчик LRU)

Цифры с реального стенда:

Операция

Время

Запись микроконтроллером нового профиля в слот на ходу, 2,2 МБ

20,8 с (из них шина QSPI 4,6 МБ/с занимает ~0,5 с, остальное — запись самой флеш-памяти)

Горячее переключение профиля из кэша (CRC слота + реконфигурация ПЛИС)

0,60–0,66 с (385 мс проверка CRC + 279 мс старт ПЛИС)

Аварийный возврат с пустого или битого слота по сторожевому таймеру

1,3 с

Схема переключения образов и аварийного возврата по конфигурационному таймеру

Схема переключения образов и аварийного возврата по конфигурационному таймеру

Три бага загрузчика за один день

Пятнадцатого октября загрузчик заработал целиком. Немного тамошних багов:

1. Профиль стартовал 7 секунд. Открытый тулчейн openXC7 пишет в заголовок битстрима регистр COR0 с полем OSCFSEL = 0: ПЛИС при перезагрузке читает свой флеш на частоте ~3 МГц. Мой упаковщик образов fbp_pack.py находит в потоке запись 0x30012001 и вписывает туда частоту 33 МГц, как у Vivado с CONFIGRATE 33. Старт ускорился до 0,56 с — в 12 раз быстрее! А, ну и подвох: битстрим, собранный в самом Vivado, так патчить нельзя — у него в конце потока стоит аппаратная проверка CRC (0x30000001), и после правки одного бита ПЛИС упадёт с CRC Error.

2. ICAP читал мусор. Чтобы golden понимал причину аварийного отката, он читает регистр BOOTSTS через примитив ICAPE2. В ответ всегда возвращалось 0xFFFFFFDB — слово состояния самого интерфейса ICAP (CFGERR_B, DALIGN, IN_ABORT_B), а не данные регистра. Я добавил отладочную команду icapdbg, которая выплёвывает 16 слов выхода ICAP подряд после CSIB = 0. Выяснилось, что данные регистра живут на выходе ровно на 4–5-м такте, а мой автомат забирал 10-й! Поменял одну константу:

// данные регистра на выходе ICAP только на 4-5 такте после CSIB=0,
// до и после - слово состояния (FFFFFFDB). Проверено на железе 2026-10-15
if (step == 4'd5) rdata <= bitswap(dout);

Сразу прочитались STAT 0x461079FC, IDCODE 0x0362C093, а после отката с пустого слота — BOOTSTS 0x00000D03 (VALID, FALLBACK). В сборках openXC7 примитив ICAPE2 у меня так и не заработал (регистры читаются нулями, IPROG ничего не делает), поэтому golden и профили с возвратом в меню я собираю в Vivado.

3. Такт SCK не выходил на ножку ESP32-S3. В драйвере SPI фреймворка ESP-IDF флаги режимов определены вложенными битами (OCTAL включает биты QUAD), а при настройке мультиплексора выводов (spi_common.c) программист написал проверку if (flags & SPICOMMON_BUSFLAG_OCTAL) без ==:

bus_iomux_pins_set_quad(host, bus_config);
if (flags & SPICOMMON_BUSFLAG_OCTAL) {      // true уже при одном флаге QUAD!    
  bus_iomux_pins_set_oct(host, bus_config);
}

Просишь QUAD — драйвер включает 4-битный режим и тут же следующей строкой перетирает SCK и IO0–3 восьмибитной функцией IO_MUX, отключая тактовый сигнал от пина! Строкой выше, в проверке ножек, тот же флаг сравнивали правильно: (flags & OCTAL) == OCTAL. Решение? — Не передавать флаг QUAD — драйвер сам включает 4-битный режим по наличию пинов WP/HD.

Ещё четыре грабли со стенда: непропай P3, ключ FBKY, HDMI на 4 мА и кнопки
  • Гребёнка P3: из 7 линий ESP↔ПЛИС сначала доходили только 2. Перепаял, прозвонил тестовым битстримом wiretest_p3. Пин прерывания IRQ на GPIO46 мешал прошивке ESP (strapping-пин), переехал на GPIO5.

  • Мусор при перезагрузке ESP: открытие COM-порта на ПК перезагружает ESP32-S3, и болтанка на шине уводила golden в BOOT. Теперь опасные команды (ERASE, PROG, BOOT, TUNE, LA_ARM) требуют 4-байтный ключ FBKY в кадре.

  • HDMI на одиночных выводах: на отладочной плате разъём HDMI разведён на восемь одиночных пинов LVCMOS33, а не на дифференциальные пары. Собрал псевдодифференциальный TMDS с программной инверсией N-линий и ODDR 5x в режиме 640x480. Декодер в Verilator сверил все 1,5 млн пикселей кадра. Но мой монитор Samsung C32R50 при стандартном токе драйвера DRIVE = 8 мА показывал чёрный экран (притом без плашки «Нет сигнала», то есть сигнал был), а при снижении тока до 4 мА сразу выдал чистую картинку!

  • Кнопки: первую раскладку посадил на GPIO35–37, а у модуля N16R8 они заняты Octal PSRAM — ESP ушёл в цикл перезагрузок. Перенёс на свободные пины.

Ретроконсоль: почему три приставки не поместились в один образ

Зачем в приборе электронщика приставка? Все и так знают =) А кроме отдыха это лучший комплексный тест платформы: память SDRAM, видео, пересечение тактовых доменов и кнопки работают одновременно, и любая ошибка видна сразу глазами.

Двадцать четвёртого октября в журнале появилась строчка: «Завёл HDMI. Портировал NES и собрал самодельный джойстик. Super Mario Bros. 3 работает!» Ядро NES — форк NESTang, вокруг него моя обвязка: такты, контроллер SDRAM (окно достоверного чтения 13,3 из 15,56 нс периода на 64,29 МГц), загрузчик ROM с флеша ESP, кнопки и скейлер видео.

Следом я интегрировал в проект ядра Mega Drive (MDTang) и SNES (SNESTang) и попробовал собрать все три консоли в один монолитный битстрим. Выяснилось, что неактивные ядра в сбросе всё равно занимают свои таблицы LUT и память: объединённая сборка съела 99,61 % слайсов Artix-7 (8 118 из 8 150) и провалила статический временной анализ с запасом WNS = −7,000 нс.

И тут во всей красе пригодилась наша подгрузка битстримов на ходу! Я разделил приставки во времени: в меню одна карточка «Ретро» с общим списком игр, а под каждую консоль в слотах флеша лежит свой отдельный битстрим (retro-nes.fbp, retro-md.fbp). Выбираешь в списке Sonic 3 — микроконтроллер видит расширение картриджа, за 0,6 секунды переключает ПЛИС в схему Сеги и тут же заливает в SDRAM саму игру! В отдельном образе Mega Drive занял всего 37 % LUT, прошёл тайминги с запасом +1,246 нс, и 29 октября — прямо накануне нашего выступления на Тыкворкинг’26 в МЭИ — Сега ожила на стенде! На конференцию мы привезли уже 12 игр для Денди и Сеги (Super Mario Bros. 3, Darkwing Duck, Crystalis, Sonic 3, Road Rash 3, Rock n' Roll Racing, Ultimate Mortal Kombat 3), и весь вечер стенд без единого зависания отработал в руках гостей. А у SNES я сейчас дожимаю расписание контроллера памяти — историю портирования всех трёх консолей расскажу отдельно, когда доведу третью приставку до экрана, там материала на хорошую статью!

Статус на конец октября

Статус на конец октября

❯ 6. Логический анализатор: проверка дошла до проводов

Первый анализатор в проекте появился раньше самого профиля и не от хорошей жизни. Пятнадцатого октября шина ESP↔ПЛИС стабильно рвала кадр чтения на 42-м байте. Осциллографа у меня нет, внешнего ЛА тоже. Зато на столе лежит ПЛИС — а внутри ПЛИС можно собрать прибор, чтобы посмотреть на саму ПЛИС!)

Добавил в golden маленький модуль la_capture: 8 внутренних линий шины, запись 4096 выборок с шагом 10 нс от спада CS# и выгрузка hex-строкой в UART:

Armed: if (p2[1] && !p1[1]) state <= Cap;   // спад CS# запускает запись
Cap: begin  wa <= wa + 12'd1;                           
// 4096 выборок по 10 нс (100 МГц)  
if (wa == 12'(Depth - 1)) state <= Head;    
  // дальше выгрузка "L<hex>" в UART
end

Питоновский скрипт на ПК разложил дамп на фронты, и первый же захват показал, на чём обрывается чтение: посреди кадра на линии CS# проскакивала единица длительностью ровно в одну выборку (шаг сетки 10 нс), и ведомый приёмник честно считал это концом кадра! Предположил наводку на макетке и добавил в qspi_slave.sv цифровой фильтр:

// кадр кончается, только если CS#=1 держится 4 такта подряд (40 нс)
end else if (cs_hi != 3'd4) cs_hi <= cs_hi + 3'd1;
else active <= 1'b0;
// такт SCK принимается, когда две выборки подряд совпадают
if (sck_s[1] == sck_s[2]) sck_q <= sck_s[1];

После этого 500 пакетов по 8 КБ туда и обратно на 10 МГц и 200 на 5 МГц прошли с нулём ошибок (4,6 МБ/с). А через десять дней, 25 октября, из этой идеи за один день вырос уже отдельный полноценный профиль анализатора на 16 каналов и 400 MS/s.

Зачем ему своя память и откуда 400 MS/s при логике на 100 МГц

На стенде анализатор буферный: он быстро пишет окно в блочную память ПЛИС (64 блока RAMB36, или 256 КиБ), останавливается по триггеру, рисует дорожки на мониторе и отдаёт запись в компьютер для PulseView. В диагностическом режиме полное окно 256 КиБ уезжает в ПК через текстовую консоль ESP в hex за 13 секунд (~20 кБ/с)... Ну, зато глазами видно! Причём после остановки память замораживается и читается по адресам, а не высыпается из одноразового FIFO: если передача оборвалась, захват можно выгрузить повторно, сверив CRC32 каждого блока и номер эпохи захвата.

Тракт буферного анализатора на стенде: 800 МБ/с на входе в BRAM и защищённая CRC выгрузка в PulseView

Тракт буферного анализатора на стенде: 800 МБ/с на входе в BRAM и защищённая CRC выгрузка в PulseView

Чтобы не разгонять всю логику кольцевого буфера и триггеров до 400 МГц, входной сэмплер отделён от ядра. Я прошёл три ступени:

  1. 100 MS/s (IOB): один отсчёт за такт 100 МГц.

  2. 200 MS/s (IDDR): входной примитив ловит данные по обоим фронтам такта 100 МГц и отдаёт по 2 отсчёта за такт.

  3. 400 MS/s (ISERDESE2): аппаратный последовательно-параллельный преобразователь прямо на каждой входной ножке ПЛИС. Он принимает данные по обоим фронтам такта 200 МГц (номинальный шаг 2,5 нс) и выдаёт внутрь ПЛИС пачку из 4 отсчётов на спокойном такте 100 МГц!

Три режима сэмплера: ISERDESE2 даёт 4 отсчёта за один такт основной логики 100 МГц

Три режима сэмплера: ISERDESE2 даёт 4 отсчёта за один такт основной логики 100 МГц

Шестнадцать каналов в два байта на 400 MS/s — это поток 800 МБ/с внутри ПЛИС. Буфер на 131 068 отсчётов заполняется за 327,67 мкс: до события память крутится кольцом (сохраняя предысторию), а после триггера дописывает заданную часть окна и останавливается. С экрана по умолчанию включается децимация до 10 MS/s — куда больше на этих макарошках из проводов?

Окно захвата: кольцевой буфер сохраняет и предысторию до события, и сигнал после триггера

Окно захвата: кольцевой буфер сохраняет и предысторию до события, и сигнал после триггера

Почему 786 408 безошибочных отсчётов не проверили вход

Сначала я проверил цифровую часть в симуляторе на официальных моделях AMD (UNISIM для IDDR и шифрованной SecureIP в Vivado Simulator для ISERDESE2). Затем прошил профиль на стенд, подал на захват внутренний тестовый счётчик и снял 6 полных буферов на 400 MS/s и 17 угловых сценариев: 786 408 отсчётов, ноль ошибок!

Красота? Только внутренний счётчик в этой схеме стоял после входного сэмплера:

Граница внутреннего теста: счётчик проверил память, триггер и выгрузку, но физические пины P2, сэмплер ISERDESE2 и провода остались за бортом

Граница внутреннего теста: счётчик проверил память, триггер и выгрузку, но физические пины P2, сэмплер ISERDESE2 и провода остались за бортом

Чтобы проверить настоящий входной тракт, понадобилась физическая петля наружу. На соседней гребёнке P6 (банк 35) я поднял 8-канальный тестовый генератор (la_loopback.sv): статика, двоичный счётчик, бегущие единица и ноль, псевдослучайная последовательность PRBS-8. Внутри ПЛИС генератор к захвату не подключён — сигнал обязан выйти через физическую ножку P6, пройти по дюпонт-перемычке, войти в ножку P2 и оцифроваться в ISERDESE2. По умолчанию все выходы генератора заперты в Hi-Z и включаются только записью с 16-битным ключом 0x4C47.

Восемь выходов генератора, шестнадцать входов анализатора — значит, проверяем двумя группами по 8 перемычек (сначала D0–D7, затем переставляем провода на D8–D15 при выключенном питании). Сначала статика (проверка карты проводов), потом динамика.

На верхней восьмёрке статика тут же поймала ошибку монтажа: подаю единицу на выход T5 (жду D13), а приходит D15; подаю T7 — приходит D13.

Перепутанные местами провода P2-25 и P2-28

Перепутанные местами провода P2-25 и P2-28

Переставил местами два провода на P2, повторил тест — карта сошлась. Ну где моя внимательность?

Как в захвате появилось число 0xFC

Запускаю двоичный счётчик: 1 миллион состояний в секунду, захват на 400 MS/s. Каждое значение счётчика должно держаться ровно 400 отсчётов и сразу сменяться следующим. Но в нижней группе строгая проверка нашла 10 промежуточных слов, каждое из которых попало ровно в одну выборку (при номинальном шаге 2,5 нс):

0xDF  1101 1111   <- старое значение (400 отсчётов)
0xFC  1111 1100   <- одна выборка на переходе (шаг 2,5 нс)!
0xE0  1110 0000   <- новое значение (400 отсчётов)

Откуда взялось 0xFC между 0xDF и 0xE0? На этом переходе счётчик меняет сразу шесть битов из восьми. Снаружи ПЛИС это восемь отдельных физических проводов: в момент выборки бит 5 уже поднялся в единицу, биты 0 и 1 уже упали в ноль, а биты 2, 3 и 4 ещё задержались в старой единице!

Захват перехода DF → FC → E0: на одной выборке (шаг 2,5 нс) видна промежуточная комбинация битов из-за более позднего спада на линиях D2–D4

Захват перехода DF → FC → E0: на одной выборке (шаг 2,5 нс) видна промежуточная комбинация битов из-за более позднего спада на линиях D2–D4

Снизил частоту счётчика в десять раз (до 100 тысяч состояний в секунду) — промежуточное слово осталось на месте. Менять значения реже и делать сам физический фронт одновременным — разные вещи! При этом псевдослучайная последовательность PRBS-8 во всех прогонах прошла с нулём ошибок.

Заодно на верхней группе упал сам питоновский скрипт анализа: он проверял бегущую единицу, искал каждое прочитанное число в списке из 16 ожидаемых кодов и споткнулся о промежуточный байт 0x21 (ValueError: 33 is not in list). Починил анализатор так, чтобы неожиданный код записывался как провал строгой проверки, и прогнал те же сохранённые RAW-файлы заново без перезахвата. Отрицательный результат остался в отчёте (TRANSITION SKEW IS REPORTED, NOT HIDDEN).

Через три дня я вернулся к сырым данным

Ежели все RAW дампы сохранились (суммарно 1 126 414 отсчётов по обеим группам), я написал для статьи скрипт и посчитал прямо по этим файлам, при каких условиях выскакивают промежуточные байты:

  • Все 33 промежуточных отсчёта случились на переходах, где одновременно падают в ноль 5 и более линий. Таких переходов во всех записях было 49, и в 33 из них (67 %) поймалось переходное слово. А среди ~3 370 переходов, где одновременно падают 4 линии или меньше, промежуточных слов ровно ноль! Это хорошо согласуется с тем, что PRBS-8 в моих прогонах оказался чистым: в нём почти не бывает пяти одновременных спадов.

  • Опаздывают только спады (1 → 0). Новые единицы в промежуточном слове всегда уже стоят на месте.

  • Задержка переехала вместе с выходом генератора. Чаще всех опаздывал выход T4 (пин P6-7, шар M1): во всех 17 случаях нижней группы (где он шёл на D4) и в 10 из 16 случаев верхней (где он шёл на D12). При переходе на верхнюю восьмёрку я переставлял провода только со стороны входов P2, а на P6 они оставались на тех же ножках.

Доля промежуточных слов в зависимости от числа одновременно падающих линий: до 4 спадов — 0 %, от 5 спадов — 60–70 %

Доля промежуточных слов в зависимости от числа одновременно падающих линий: до 4 спадов — 0 %, от 5 спадов — 60–70 %

Распределение опозданий по выходам генератора T0–T7 в обеих группах

Распределение опозданий по выходам генератора T0–T7 в обеих группах

Рабочая гипотеза — эффект одновременного переключения слабых выходных буферов (SSO / Ground Bounce): 5–8 драйверов в режиме DRIVE = 4 мА, SLEW = SLOW разом тянут линии вниз, возвратный ток бежит через индуктивность земляных дюпонтов, и самые нагруженные линии пересекают порог нуля чуть позже соседей. Но строго отделить выходную площадку от провода и от входного сэмплера по этим данным нельзя — если у вас есть красивая идея, как чисто разделить их вклад на стенде без гигагерцового осциллографа, напишите в комментариях, с удовольствием проверю!)

С проводами на этот вечер я разобрался (а заодно вывел дорожки ЛА на HDMI-экран, починил шрифты и сделал безопасный демо-режим с генерацией UART/SPI/PWM с ножек ESP). Теперь вопрос попроще: откуда у двух школьников вообще взялись все эти железки?

❯ 7. Где мы взяли ресурсы и что изменило сообщество

На старте у нас двоих в карманах было не больше тысяч 15ти. Скинулись, заказали модуль ПЛИС, отладочную плату, экран, ESP32-S3 и мелочь для макета (экран, кстати, 4 октября я уже пробовал включать отдельно и спалил платку повышайки подсветки — на нынешнем стенде всё идёт через HDMI).

Дальше нужны были компоненты, паяльное оборудование и опытные люди, которые посмотрят на мои схемы. Школа помогла доступом к 3D-принтерам и оборудованию, а вот бюджета на такие проекты там нет...

Третьего октября я написал админу сообщества FPGA Systems в Telegram: можно опубликовать пост? Так и так, два десятиклассника делают открытый прибор на ПЛИС, ищем инженерную помощь и спонсоров. После публикации начали откликаться люди:

  • Андрей в тот же день оплатил наш первый счёт на компоненты в ЧипДипе.

  • crytech7 поддержала проект крупным донатом и предложила помощь с поставками деталей.

  • Благодаря переводу Виктора Белова у меня появилось нормальное домашнее оборудование: паяльная станция YIHUA 982, фен 858D, мультиметр UNI-T UT61E+, дымоуловитель и расходники.

На 30 октября публичный счётчик на сайте показывал 44 011 ₽ поступлений и 25 053 ₽ расходов: 21 042 ₽ ушло на инструмент и расходники, 4 011 ₽ — на первые компоненты, а остаток в копилке отложен под комплектацию первой печатной платы. Каждая покупка и чек открыто выложены на fabbit.dev/spent.

Сводка донатов

Сводка донатов

Мультиметр UT61E+ из этого списка уже отработал своё: 17 октября я снимал им потребление модуля i9+ на разных битстримах, чтобы оценить автономность от батареи. И первый замер вышел раз в десять меньше правды (1–13 мА)! Оказалось, тактовая кнопка питания S1 на отладочной плате нормально замкнутая и в покое шунтировала щупы амперметра. Зажал кнопку пальцем — ток стал честными 107–337 мА (0,52–1,64 Вт). Заодно я сравнил прирост входной мощности модуля от простоя к нагрузке (+0,60 и +1,12 Вт на 25 % и 50 % ПЛИС) с расчётной прибавкой самого кристалла в модели Vivado (+0,51 и +0,92 Вт). Отношение вышло около ~1,2x (с линейным стабилизатором от 5 В было бы 3–5x) — так по наклону графика я косвенно оценил, что под радиатором ядро 1,0 В питает импульсный buck-стабилизатор с КПД в районе 80–85 %.

Откликнулся и уже не раз упомянутый здесь глубокоуважаемый Артём Кашканов (@radiolok) — да-да, без него в этой статье не обошлась почти ни одна глава!) Если человек собирает безумные компьютеры из реле и радиоламп, наш школьный проект его, видимо, уже не пугает) Артём обсуждал со мной архитектуру, подкинул идею отладчика с трассировкой и USB 3.0, взялся помочь с реверсом закрытого блоба UHSIF после нашего обсуждения и заказал нам девборду CH32H417.

Поддержал нас и завод печатных плат «Резонит», согласившись помочь с изготовлением плат для прототипа. Под целевую 6-слойную плату (1,5 мм, ENIG, контроль импеданса ±10 %) я сразу сверил их технологические нормы с корпусом QFN-128 (шаг 0,35 мм) и выяснил важную деталь: паяльную маску нужно выбирать зелёную (или синюю/красную). У чёрной и белой маски минимальный масочный мостик 0,15 мм, а у зелёной — 0,10 мм, иначе между площадками выводов H417 маска просто не ляжет. Паять платы буду сам =)

Ещё у нас появился научный консультант — доцент кафедры МИФИ, и намечаются дела с YADRO (без обещаний — если договоримся, ждите меня в их лабе в следующей статье XD). А 30 октября мы впервые вывезли Fabbit в люди — я выступил с докладом на конференции пет-проектов Тыкворкинг’26 в МЭИ. Было классно: угощения, мерч, бодрые вопросы про ПЛИС, а после докладов вокруг нашего стола со стендом собиралась живая очередь поиграть в Денди и Сегу с самодельного джойстика.

❯ 8. От стенда к карманному прибору

Итак, стенд подтвердил главное: связка из постоянно живущего супервизора и ПЛИС, в которую микроконтроллер прямо на ходу подгружает нужные битстримы, работает отлично и не превращается в кирпич при сбоях. А питание от батареи, защищённые входы 0–10 В, сменный модуль-мезонин, ЛБП и USB 3.0 предусмотрены в проекте собственной платы, схему которой я сейчас рисую в KiCad 10 (для трассировки перееду на Altium).

Главный осознанный компромисс на бумаге — автономность в тяжёлых профилях. По замерам модуля и расчёту остальных узлов от аккумулятора 2800 мА·ч (9,32 Вт·ч, КПД питания 0,88) прибор в расчёте живёт 8,7 ч в меню, 5,9–7,0 ч в ретро-играх, 5,6–6,6 ч в анализаторе и около 3,1 ч в режиме двухканального осциллографа:

Расчёт времени работы от аккумулятора 2800 мА·ч по режимам

Расчёт времени работы от аккумулятора 2800 мА·ч по режимам

Изначально хотелось не меньше пяти часов везде. Осциллограф в эту планку не укладывается (быстрый АЦП и синтезатор такта берут своё), увы, но полный набор функций в кармане важнее.

Почему вообще не упростить прибор до дешёвой настольной коробки с половиной функций? Я считал урезанный вариант «Core + Lite» — он выходил втрое дешевле и куда разумнее для серии. Но мы с Яриком решили, что сначала хочется собрать один флагманский портативный прототип без компромиссов, как НИР и инженерную витрину, и набить на нём все шишки! А уже потом на базе этого опыта сделать простой и модульный настольный вариант без экрана и батареи. Правда, после переезда на CH32H417, скоростной АЦП HMCAD1511 и ЦАП DAC904 список деталей под первую ревизию платы заметно разросся и перешагнул остаток нашей копилки — но тем интереснее довести этот прототип до текстолита!

❯ 9. Финал

Следующий шаг — дочертить схему собственной платы, проверить каждый пин по даташитам, развести 6 слоёв, запаять и первым делом запустить подгрузку профилей и поток анализатора по USB 3.0.

  • Исходники, платы и корпус: github.com/fabbit-dev/fabbit. Код под MIT, железо под CERN-OHL-S-2.0, инженерный дневник — в каталоге journal/.

  • Задачи, где мне очень пригодится ваша помощь:

    • Как чисто разделить выход генератора ПЛИС, провод и входной сэмплер ISERDESE2 в петле ЛА на 400 MS/s.

    • Незамыленный взгляд на схему и будущую трассировку перед отправкой на завод.

    • Да и вообще любая инженерная подмога: если вы собаку съели на ВЧ-аналоге, быстрых платах, USB 3.0 или ПЛИС и готовы вовремя крикнуть «стой, сейчас бахнет!» — милости прошу, убережёте нас от лишнего волшебного дыма =)

  • Сайт проекта: fabbit.dev — там можно со всех сторон покрутить 3D-модельку прибора и поддержать наш проект (будем рады помощи от каждого — и советом, и деталями из BOM, и вкладом в сборку первой платы; все закупки и чеки открыто ведём на fabbit.dev/spent).

  • Телеграм-канал с новостями со стола — @fabbit_dev (моя личка для советов, критики и предложений — @sshareds).

Осталось довести это до рабочего текстолита и с серьёзным лицом объяснить на школьной защите, почему для индивидуального проекта в десятом классе жизненно понадобились двухканальный осциллограф на 400 MS/s и аппаратный глитчер питания… До встречи, Хабр!

Может быть интересно:
Перейти ↩

Перейти ↩

Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram‑канале ↩

Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.