Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
![](https://habrastorage.org/webt/4n/ii/d5/4niid5uuhjxjrpb_edyt-ilqij4.png)
Этот проект будет интересен любителям ретро игр и просто тем, кто захочет вспомнить былые дни, а может и собрать собственную карманную консоль. Здесь мы подробно разберем этот процесс для комплекта Null2, попутно решив ряд проблем совместимости и обсудив технические вариации сборки.
В детстве у меня никогда не было Game Boy, Game Gear или какой-либо другой портативной игровой консоли. Черт, да у меня и Nintendo Switch тоже не было.
Играл я в основном на ПК и приставках, а карманными устройствами мне удалось побаловаться всего дважды: раз в средней школе, когда один друг на день одолжил мне свой Game Boy, и в прошлом году, когда отец принес свой Nintendo Switch – который мои дети быстренько прихватизировали.
Думаю, из чувства зависти я решил, что первым делом последнюю разработку Raspberry Pi, а именно Pi Zero 2 (мой обзор на него можно почитать здесь (англ.)), использую для сборки собственной портативной ретро-консоли.
Ну а что подойдет для этого лучше, чем комплект Null 2 (фото выше, взято с Tindie). Он состоит из готовых компонентов и кастомной печатной платы, которые аккуратно вписываются в акриловый корпус.
![](https://habrastorage.org/webt/3a/m1/_3/3am1_3hbahjfp5kmrwhkxzhjur0.png)
Наконец-то, у меня появилась собственная карманная консоль – даже лучше, я сам ее собрал! Я даже заточил под нее часть ПО, поскольку официальный образ Null 2 – по крайней мере на момент написания статьи – не работает на оборудовании Pi Zero 2.
Если что, я загрузил подробное видео процесса сборки на свой YouTube-канал:
Оборудование
По итогу всего этого проекта даже не знаю, стал бы я рекомендовать набор Null 2 людям без опыта работы с паяльником. А может и стал бы. Ведь за время сборки мне удалось попрактиковаться в:
- сквозном монтаже компонентов;
- поверхностном монтаже;
- поверхностной пайке шлейфов;
- выпаивании (из-за нескольких промахов).
Фото моего рабочего стола:
![](https://habrastorage.org/webt/jn/l5/8v/jnl58vv4w4ivwycxxy_w_ohvew8.png)
А вот все использованные компоненты с партнерскими ссылками на Amazon:
- паяльная станция Weller WES51;
- бутылек Menda Alcohol (не мой любимый, но он содержит 91% изопропилового спирта, для чистки деталей);
- регулируемые стрипперы WS-5 (очень удобны для зачистки проводов);
- микрокусачки Dowell (для откусывания выводов впритирку к плате);
- длинногубцы Hakko;
- пинцет Hakko CHP 7-SA (без него у меня работать с SMD-компонентами никак не получается);
- термостойкая лента APT 1мм 1" Kapton (использовалась на нескольких этапах);
- оплетка для выпайки и экстрактор припоя AUSTOR (ошибки для меня обычное дело, так что эти инструменты помогают их исправлять).
В итоге я также использовал флюс, припой и ватные палочки для чистки деталей спиртом после неосторожного проливания на них флюса:)
Самой щепетильной задачей оказалось припаивание Pi Zero 2 к Null 2. Первым шагом нужно приклеить его к плате для выравнивания с монтажными площадками:
![](https://habrastorage.org/webt/ox/h3/lh/oxh3lhu0yoedmg4hphud4q2jr6s.png)
Это странный метод пайки. Думаю, его можно назвать «слепая пайка через отверстия», ведь вы, по сути, «заполняете» припоем отверстия в местах контактов GPIO Pi и надеетесь, что припой доберется до контактной площадки под платой.
По счастливому стечению обстоятельств все контакты GPIO успешно прошли тестирование, кроме GND, который используется Null 2. В итоге мне пришлось прокинуть отдельную перемычку к одному из других контактов заземления на Zero 2.
![](https://habrastorage.org/webt/mw/j5/dx/mwj5dxzh6zseivqio1yqlxnghcq.png)
В целом я собой не горжусь, но это мой первый опыт пайки через отверстия, так что 39/40 успешных соединений можно назвать неплохим средним результатом. Позднее я поменял эту красную перемычку на тонкий эмалированный медный провод, который лучше вписывался в корпус.
После этого промаха все пошло как по маслу, хотя пайка кое-каких SMD-компонентов (например, резистор на фото выше) может несколько напрягать. К счастью, в комплекте только несколько кнопок, резистор и экран, которые монтируются поверхностно.
![](https://habrastorage.org/webt/a-/eb/hf/a-ebhfndjpf-opu0pg-acva2gqq.png)
Главное следовать такому алгоритму: нанести немного флюса на соединение, после чего его пропаять. Если вы случайно переборщите с припоем, то возьмите оплетку для его удаления и уберите излишки. Протрите и повторите.
![](https://habrastorage.org/webt/m3/j-/_y/m3j-_ymiqi4bcffgg1wa4-ru66a.png)
Флюс в помощь
Как бы то ни было, я установил аккумулятор, зарядил его через USB-C, затем подал питание на плату и…ничего не произошло!
Я решил, что что-то сломал, но после повторного тестирования всех контрольных точек проблем с подключением оборудования не обнаружил. В конечном счете я выяснил, что проблема была в официальном образе Null 2 Pi (по крайней мере на момент написания статьи), который не включал файлы дерева устройств (
dtb
) для Pi Zero 2.После смены на официальный образ Pi OS малинка загрузилась, но здесь возникла другая проблема…
Программное обеспечение
Собрать RetroPie на образе PI OS не так-то просто, и это требует немало времени, если точнее, то множество часов. И, как я в итоге выяснил спустя пару дней, пока что собрать его на 64-битной Pi OS нельзя. При этом у меня также возникли сложности со сборкой и на 32-битной версии Zero 2.
В итоге я решил попробовать кастомизировать образ RetroPie OS, чтобы эта система загружалась, а с ней работало и все оборудование (экран, кнопки и аудио).
На сайте Null 2 можно скачать наборы инструкций для «создания собственного» образа. К сожалению, эти инструкции несколько отстали от текущей версии Linux, поэтому я опишу каждый шаг подробно.
Скачивание RetroPie
Поскольку готовые образы RetroPie Raspberry Pi уже содержат версию Pi 3, а в Pi 3 используется тот же процессор, что и в Pi Zero 2, то этот образ должен подойти, если записать его на microSD…
Но я выяснил, что WiFi-микросхема в Zero 2 несколько отличается от используемой в Zero W и 3 B+, с которым совместим текущий образ RetroPie (ноябрь 2021). Ввиду этого потребуется более свежая версия ядра, чтобы скачать верный драйвер
brcmfmac43436
для Zero 2. Так что, если вам нужен рабочий WiFi и Bluetooth, то до официального релиза версии старше 4.7.1 придется скачивать еженедельную сборку RetroPie.После записи образа на MicroSD нужно будет настроить его для удаленного доступа, поскольку Null 2 не позволяет использовать порты USB или HDMI для подключения дисплея.
![](https://habrastorage.org/webt/9s/lh/qi/9slhqi0wh8ubi159b-gple448ug.png)
Перед записью образа на карту нужно будет с помощью Shift+Ctrl+X перейти к Raspberry Pi Imager для редактирования RetroPie OS. Среди этих настроек необходимо либо установить SSH-пароль, либо вставить публичный SSH-ключ, который позволит вам авторизовываться. Здесь же нужно сохранить учетные данные для доступа к WiFi.
Я установил имя хоста как
null2
, чтобы получать доступ к Pi через null2.local
в своей сети (не выясняя его IP-адрес). Сохраняем настройки и записываем образ RetroPie на MicroSD-карту.
Затем вставляем эту карту в Pi Zero 2 и загружаем его – первая загрузка скорее всего займет пару минут, так как малинке нужно будет развернуть файловую систему, а RetroPie выполнить ряд действий, включая генерацию нового SSH-ключа хоста.
После загрузки у вас должно получиться удаленно подключиться к Pi через SSH, используя
pi@null2.local
(если вы выбрали это имя хоста).Если подключиться у вас не получается, то причина может быть в некорректном включении WiFi в образе RetroPie. Проще всего в этом случае взять второй Pi Zero 2 или 3B+, вставить в него карту с образом, подключить этот Pi к дисплею, клавиатуре и мыши, после чего настроить WiFi уже там. По завершению можно будет переставить карту обратно.
Теперь пора заняться аппаратной частью Null 2. Сначала дисплей:
Настройка дисплея ILI9341 SPI
![](https://habrastorage.org/webt/sy/73/_o/sy73_o65m9x92m3tuxyz_n-gx6s.png)
Поскольку модуля
fbtft_device
больше в ядре Linux нет, мне пришлось использовать для дисплея драйвер juj/fbcp-ili9341. Этот драйвер позволяет управлять через SPI небольшим дисплеем 240х320 на частоте 60Гц, что весьма неплохо.Однако скомпилировать его на Pi оказалось не так просто, поскольку пришлось переводить некоторые присваивания контактов Null 2 в команды компиляции. Вот, что я проделал на самом Pi через SSH, чтобы дисплей заработал изначально:
cd ~
sudo apt-get install cmake
git clone https://github.com/juj/fbcp-ili9341.git
cd fbcp-ili9341
mkdir build
cd build
cmake -DILI9341=ON -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_RESET_PIN=25 -DSPI_BUS_CLOCK_DIVISOR=6 -DSTATISTICS=number ..
make -j
sudo ./fbcp-ili9341
По завершению этого процесса драйвер должен начать отображать на дисплее экран малинки:
![](https://habrastorage.org/webt/ly/pf/4x/lypf4xqeo8mzxguqylqc9edxjcg.png)
Для прекращения отображения нажмите Ctrl+C. Он немного размыт, так как разрешение HDMI не совпадает с дисплеем SPI, что можно исправить редактированием файла
/boot/config.txt
(sudo nano /boot/config.txt
), добавив в его начало следующие настройки HDMI:hdmi_group=2
hdmi_mode=87
hdmi_cvt=320 240 60 1 0 0 0
hdmi_force_hotplug=1
Далее мне пришлось сделать так, чтобы экран включался при загрузке. Следуя
README
драйвера, я открыл для редактирования /etc/rc.local
с помощью sudo nano /etc/rc.local
и добавил перед заключительной строкой exit 0
следующее:# Активирует драйвер дисплея ILI9341
sudo /home/pi/fbcp-ili9341/build/fbcp-ili9341 &
Затем я перезагрузил Pi, чтобы убедиться в запуске экрана. И он появился! Только кверху ногами… Я открыл настройки загрузки с помощью
sudo nano /boot/config.txt
и добавил рядом с конфигурацией HDMI следующую строку для поворота экрана:display_rotate=2
После перезагрузки он отобразился как положено.
Ввиду специфики функционирования дисплея по SPI вы можете наблюдать тиринг или прочие артефакты, в зависимости от используемой модели Pi, ее разгона и других настроек. Более подробно о решении подобных проблем можно почитать в README
в репозитории драйвера дисплея.
Настройка кнопок
![](https://habrastorage.org/webt/hv/-d/bg/hv-dbg23d1bueneitvw-oysiqay.png)
Следуя инструкции к Null 2, для добавления программного управления кнопками с помощью
retrogame
я воспользовался Retro Gaming Guide от Adafruit:mkdir ~/Scripts && cd ~/Scripts
curl https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/retrogame.sh >retrogame.sh
sudo bash retrogame.sh
В предложенном меню выберите первую опцию (мы это позже переопределим) и нажмите ввод.
Когда снова возникнет меню выбора, перезагрузите устройство. Затем откройте конфигурацию
retrogame
командой sudo nano /boot/retrogame.cfg
и поместите в него содержимое файла boot/retrogame.cfg
, который идет в связке с другими ресурсами кастомного образа Null 2. Вот интересующие нас части этого файла:LEFT 04 # Joypad left
RIGHT 17 # Joypad right
UP 15 # Joypad up
DOWN 27 # Joypad down
LEFTCTRL 22 # 'A' button
LEFTALT 23 # 'B' button
Z 02 # 'X' button
ENTER 13 # 'Start' button
SPACE 16 # 'Select' button
X 03 # 'Y' button
A 06 # 'L' button
S 12 # 'R' button
Y 05 # Exit button
После сохранения файла перезагрузите Pi. Теперь назначения клавиш должны работать. Проще всего убедиться в этом можно, нажав на кнопку System (внизу слева на обратной стороне платы) и посмотрев, напечатается ли символ
Y
в окне поиска. Если да, то назначения кнопок работают – отлично!Кнопки управления системой (выключение и регулирование громкости)
Документация кастомного образа Null 2 включает скрипт
systembuttons.py
. Мне пришлось немного его изменить под Python 3. Вот последняя версия этого файла: #!/usr/bin/python3
# Отключение устройства и регулировка громкости
import keyboard
import time
import os
INITIAL_VOLUME = "25%"
def shutdown():
os.system("sudo shutdown -h now")
def volumeUp():
os.system("amixer sset -q 'Master' 5%+")
def volumeDown():
os.system("amixer sset -q 'Master' 5%-")
# Инициализация громкости в INITIAL_VOLUME
os.system("amixer sset -q 'Master' " + INITIAL_VOLUME)
keyboard.add_hotkey('y+s', callback=volumeUp)
keyboard.add_hotkey('y+a', callback=volumeDown)
keyboard.add_hotkey('y+left alt', callback=shutdown)
keyboard.wait()
view rawsystembuttons.py hosted with ❤ by GitHub
В
/home/pi/Scripts/systembuttons.py
нужно будет вставить следующий фрагмент:mkdir ~/Scripts
nano ~/Scripts/systembuttons.py
# Вставить это содержимое в файл
Я также заметил, что этот скрипт использует библиотеку Python
keyboard
, которой нет в дефолтном дистрибутиве Pi OS, и решил ее добавить:sudo apt update
sudo apt install -y python3-pip
sudo pip3 install keyboard
Далее я открыл
/etc/rc.local
с помощью sudo nano /etc/rc.local
и добавил перед заключительной строкой exit 0
следующее:# Включает кнопки управления системой Null 2
sudo python3 /home/pi/Scripts/systembuttons.py &
Чтобы их проверить, я перезагрузил девайс, нажал кнопку System и кнопку B (нижняя на правом навигационном джойстике). Система отключилась, супер!
Настройка аудио для PCM5102a
![](https://habrastorage.org/webt/bq/yo/tq/bqyotq67skrzsp6f0o-t3r9cehc.png)
В Null 2 используется типичная аудиоплата PCM5102a, и HiFi-Berry поддерживает ее нативно. Все, что нужно – это открыть файл загрузочной конфигурации с помощью
sudo nano /boot/config.txt
и внести следующие изменения:# Эта строка должна быть закомментирована.
#dtparam=audio=on
# Добавьте эту строку в конец файла
dtoverlay=hifiberry-dac
Перезагрузите и проверьте, появилась ли звуковая карта в выводе команды
aplay -l
:pi@null2:~ $ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: sndrpihifiberry [snd_rpi_hifiberry_dac], device 0: HifiBerry DAC HiFi pcm5102a-hifi-0 [HifiBerry DAC HiFi pcm5102a-hifi-0]
Subdevices: 1/1
Subdevice #0: subdevice #0
Чтобы установить это устройство для воспроизведения звука по умолчанию и включить управление громкостью, выполните
sudo nano /etc/asound.conf
и вставьте следующую конфигурацию:pcm.!default {
type plug
slave.pcm "speakerphat"
}
ctl.!default {
type hw card 0
}
pcm.speakerphat {
type softvol
slave.pcm "plughw:0"
control.name "Master"
control.card 0
}
В оригинальном образе Null 2, выполняющемся на старой версии Pi OS и ALSA удалось задействовать аппаратное управление громкостью с помощью простой конфигурации. Но после некоторых поисков в сети я понял, что для более новых версий требуется использование softvol, как мы настроили выше, поскольку ЦАП PCM5102A является старой моделью, и для прямого аппаратного управления громкостью больше не поддерживается.
Снова перезагружаем, и можно протестировать воспроизведение WAV-файла:
aplay /usr/share/sounds/alsa/Front_Center.wav
Если звук на Null 2 не отключен, вы должны услышать голос, произносящий “Front…Center”. Он может быть довольно громким.
Для убавления громкости нужно будет нажать System и левую дополнительную кнопку (верхняя левая часть платы снизу). Чтобы прибавить его нужно нажать ту же System и правую дополнительную кнопку.
Если управление громкостью не заработает, причина может быть в том, что команда в скриптеsystembuttons.py
не подходит для вашей платы. Выполнитеamixer
и посмотрите, как обозначенSimple mixer control
. Если это неMaster
, то вам нужно изменить его значение в скрипте на то, которое указано на плате.
![](https://habrastorage.org/webt/0s/rm/or/0srmorinqjhaavunrfeee0afcxs.png)
Микрофонный усилитель тоже должен работать – чтобы его использовать, просто подключите наушники. Хотя динамики автоматически не отключаются, так что это при необходимости придется делать это вручную.
Настройка RetroPie
Прежде чем полноценно погрузиться в одну из желанных старых игр, я решил уделить немного времени настройке RetroPie под свой вкус.
Первым делом я перешел в ES Themes на экране конфигурации RetroPie и установил тему anthonycaccese/tft. Далее я нажал Start и поменял тему TFT в UI Settings > Theme Set.
Для моего уже взрослого взгляда эта тема выглядела куда более пригодной, нежели предустановленная Carbon.
Далее мне захотелось добавить заставку при выборе игр. Для этого я перешел в Scraper, расположенный в Main Menu (для доступа нажмите Start) и выбрал Scrape Now. Теперь экран выбора игр стал намного симпатичнее:
![](https://habrastorage.org/webt/px/zd/ks/pxzdksz6kqxdubfzf-d2emdp05w.png)
Последним делом я решил настроить отображение FPS во время игры – в прошлом Pi Zero высмеивали в качестве серьезной машины для ретро гейминга, так как он тормозил даже на простецких проектах NES.
Отображение FPS – это опция RetroArch, поэтому для ее активации я отправился в меню конфигурации RetroPie, где выбрал RetroArch. В меню RetroArch я перешел по маршруту Settings > On-Screen Display > On-Screen Notifications > Notification Visibility > Display Framerate, где выбрал ON. Для сохранения настройки я вернулся в Configuration File > Save Current Configuration.
![](https://habrastorage.org/webt/9x/oh/aa/9xohaapnlff4z09ayo8qu6ayjug.png)
Наблюдаемые 58-59 FPS даже в более требовательных играх NES и Genesis/Megadrive позволяют мне уверенно сказать, что Null 2 намного интереснее работает на 60Гц с Pi Zero 2.
Подробнее о производительности я расскажу на YouTube, но пока мне кажется, что Zero 2 без особых проблем потянет большинство проектов NES, SNES, GBA, PS1, Genesis/Megadrive и даже некоторые игры N64.
Корпус
Я решил заказать лазерную нарезку акриловых деталей по спецификациям Null 2. Для этого можно либо выбрать одну из рекомендованных Ampersand компаний (я выбрал RazorLAB), либо скачать файлы и нарезать заготовки самостоятельно (если у вас есть доступ к лазерному резаку и листовому акрилу).
![](https://habrastorage.org/webt/xr/8p/rm/xr8prmjp1clm2q4foexvot7rvrw.png)
Кроме того, есть набор STL-файлов для 3D-печати корпуса Null 2, что может выйти немного дешевле (хотя в итоге он получится не таким красивым).
Если вы склонитесь к варианту с акрилом, то самыми сложными частями процесса будут «сваривание» нескольких деталей воедино и подгонка кнопок под корпус шлифовкой.
Для соединения деталей я купил Weldon #4 с бутыльком-дозатором. Рекомендую работать с ним очень осторожно. Убедитесь, что в комнате хорошая вентиляция, подстелите что-нибудь на случай протекания излишков (я заметил, что он отлично снимает краску…) и старайтесь спринцевать под каждую деталь чуть с избытком – жидкость хорошо распределяется по всей поверхности, а если ее между склеиваемыми деталями вдруг окажется недостаточно, то образуются мелкие пузырьки.
![](https://habrastorage.org/webt/qo/y2/ia/qoy2iaj9z5co-hewvequdcia6as.png)
При этом все нужно выравнивать идеально, так как переделать уже не получится.
Шлифовать мне порядком поднадоело, так как для четкой установки кнопок с резиновыми прокладками стачивать пришлось довольно много. Сам же процесс был довольно прост: я положил на стол кусок 120 наждачки и прошелся по нему каждой кнопкой и D-падом, пока они не приняли нужный размер:
![](https://habrastorage.org/webt/mo/tu/zu/motuzuin1og_u1dsfg-qu4miiri.png)
К слову
Несколько замечаний по RetroPie:
- Счетчик FPS на дисплее 320х240 получается крохотный, и я не смог разобраться, как его увеличить.
- Если перейти в игровое меню RetroArch, то можно делать скриншоты и даже производить запись, но последнее может сильно сказаться на быстродействии игры. Полученные файлы сохраняются в каталоге
/home/pi/.config/retroarch
.
Над чем я еще работаю:
- Когда заряд аккумулятора опускается ниже 50%, во время серьезной нагрузки яркие части дисплея начинают мерцать. Было бы здорово как-то избавиться от этого мерцания.
- Разгон работает, но корпус недостаточно хорошо отводит тепло, поэтому спустя несколько минут геймплея начинается троттлинг. Думаю, на стоковой сборке Null 2 лучше придерживаться частоты в 1Ггц. В качестве решения можно попробовать врезать с задней стороны теплоотвод.
- Я пытался наладить работу устройства на 64-битной Pi OS, но столкнулся с двумя проблемами: во-первых, процесс установки исходников RetroPie вызвал ряд ошибок, с которыми я так и не разобрался. Во-вторых, драйвер дисплея в этом случае может заработать, а может и нет – пока что.
- Опция
display_rotate=2
поворачивает изображение, выводимое по HDMI и SPI. На деле можно сделать так, чтобы поворачивался только вывод по SPI. Для этого нужно изменить одну из опций драйвера при его компиляции.
Что мне в Null 2 не понравилось:
- Шлифовка кнопок оказалась муторной.
- Было бы неплохо иметь аналоговую крутилку для регулировки громкости. Способ с горячими клавишами несколько неудобен, и правильно реализовать его в ПО было сложновато.
- Не регулируется подсветка, так что ночью использовать девайс не очень приятно для глаз.
- Присутствует предупреждение о том, что устройство нельзя использовать во время зарядки, хотя при изучении информации по плате TP4056 я нашел неоднозначные результаты относительно того, защитит ли она аккумулятор от токовой перегрузки, если продолжать использовать полностью заряженный Null 2, не отключая его от сети. Думаю, лучше следовать рекомендации и во время зарядки его не использовать.
Заключение
Вам наверняка знакома фраза «Главное не цель, а само путешествие». Считаю, что именно это я усвоил за время налаживания работы Null 2 с Pi Zero 2 W.
К сожалению, мне не удалось заставить работать новехонькое (еще не вышедшее) оборудование на плате, изначально созданной для более старого Pi Zero. К тому же, иногда было нелегко найти нужную помощь или задать вопросы, так как я не мог просто сказать: «ну, оно не работает, потому что это другая плата…»
Хотя в целом этот проект оказался интересен, и мне нравится, как компактно и элегантно он смотрится на моем столе. Я уже дал опробовать игрушку своим ребятишкам. Вряд ли в их юных бойких руках она долго протянет, но тот факт, что каждую деталь (быть может, кроме Pi Zero, который будет сложно выпаять) можно заменить недорогим повсеместно доступным аналогом, доставляет мне внутреннюю радость.
Я рекомендую Null 2 всем, кто реально хочет заиметь портативную ретро-консоль из 90-х. Если же вам захочется использовать нечто более готовое, чтобы можно было просто всунуть туда Pi и начать играть, то этот набор не для вас.
Сейчас Null 2 на Tindie закончились, но Ampersand наверняка уже работает над новой партией. Надеюсь, что все желающие заполучить такое развлечение в скором времени смогут заказать себе набор!
![](https://habrastorage.org/webt/ou/g5/kh/oug5kh6sjydt9llengsiebnp40w.png)