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

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

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

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

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

Рендер будущего устройстваРендер будущего устройстваПолный список того, что заложено в целевую плату (ТТХ и начинка)

  • Двухканальный осциллограф: 8-битный АЦП HMCAD1511, 2×312–375 MS/s штатно и 2×400 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-экране (640×480) и полноразмерном 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 2×40 (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 2×40. Мезонин сделан съёмным специально ради модульности: на его разъём выведены 35 быстрых линий ПЛИС и питание, так что простой перестановкой платки мезонина в прибор можно добавлять совершенно новые аппаратные функции (штатно туда ставится модуль осциллографа, генератора и мультиметра, а при желании можно воткнуть свою плату под SDR, специфичные интерфейсы или автоэлектронику).

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

Профиль

Что делает

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

Статус

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

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

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

на стенде 16×400 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

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

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

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

сменный модуль-мезонин (BergStak 2×40), 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 КиБ) идут в адресном пространстве подряд — так что полный кадр 640×480 в 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 в карманном корпусе места нет). Расплатились задней крышкой: когда мезонин вырос до 73×37,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 рисует меню (640×480, 4 бита на пиксель), а ПЛИС выводит его на HDMI.

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

Карта 16-мегабайтного флеша ПЛИС (MX25L12833F)

0x000000 golden, 4 МиБ, защищён аппаратно битами BP=7, TB=10x400000 слот 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-15if (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 в режиме 640×480. Декодер в 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" в UARTend

Питоновский скрипт на ПК разложил дамп на фронты, и первый же захват показал, на чём обрывается чтение: посреди кадра на линии 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 и аппаратный глитчер питания… До встречи, Хабр!

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

  • Октябрьский дайджест — видео и логи запросов в AI Gateway, PR-стенды и серверы с GPU

  • Сверло, скрепка и пинцет. Как прошивали консоли до того, как это стали делать нейросети

  • Что умеет «486SX на максималках»? Запускаем промышленный мини‑ПК из двухтысячных

Перейти ↩Перейти ↩

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

Источник: habr.com

0 0 голоса
Рейтинг новости
1
0
Подписаться
Уведомить о
0 комментариев