Raspberry Pi в картридже от NES

в 16:27, , рубрики: diy или сделай сам, pi, Raspberry, retropie, игра, Игры и игровые приставки, приставка, Разработка на Raspberry Pi, ретро, эмулятор
Raspberry Pi в картридже от NES - 1

Здравствуйте! Это ретро игровая приставка на базе Raspberry Pi. В картридже от игровой приставки NES. Для игры может использоваться интегрированный экран. При выводе же видео по HDMI он показывает изображение обложки игры, а также температуру ядра, см. фото. Предлагаю немного понастальгировать и почитать про сборку и настройку такого устройства. Осторожно, далее много трафика и фото.

Ностальгия

В детстве мы, кому сейчас за 25-35, любили играть в приставки. Тогда не было новомодного слова консоли, поэтому буду называть их так. Мое знакомство с приставками началось с Денди (клон NES). Super Mario Bros, Contra, Ducktales, Battletoads это лишь часть хитов того времени. Затем всем двором собирались поиграть у моего друга в Сегу (Sega Mega Drive), в такие хиты как Sonic, Ultimate Mortal Combat 3, Contra Hard Corps и другое. А уж когда вышла Play Station, надо сказать, она добралась к нам не сразу, то серия Resident Evil вызывала какой-то по истине пугающий восторг.

Raspberry Pi в картридже от NES - 2

Смахнуть слезу ностальгии мне помогла эта картинка. Надо сказать, я не первый, кто придумал вставить Raspberry Pi в корпус от картриджа NES. Да, это не мое устройство. И этот картридж подходит для этих целей практически идеально, он маленький и красивый. А внутри много места. Судите сами.

Raspberry Pi в картридже от NES - 3

Внутри Raspberry Pi Zero, USB хаб, и пара удлинителей. Все палки посажены на гов термоклей.

Сборка

Захотелось собрать нечто тоже самое или похожее. Был выбран такой же картридж от NES. Другие варианты либо совсем маленькие, либо выглядят не очень. В качестве пламенного сердца ретро-машины выступил Raspberry Pi 3B. Были закуплены на али, также, USB разъемы с удобными выводами для пайки. Вот это вот всё.

Raspberry Pi в картридже от NES - 4

Ах да, будете повторять этот проект, не берите хитовые картриджи. Их и так мало осталось. Возьмите что-нибудь более распространенное или менее известное. Есть также вариант взять картридж с али, но оригинал, он душу греет. Мой 1986 года выпуска.

Также вам понадобится специальная отвертка nes screwdriver, если картридж закручивается на три шурупа. Есть также ранние варианты картриджей с пятью шурупами, они откручиваются обычной плоской отверткой. У меня как раз такой.

С картриджа канцелярским ножом и полотном от ножовки по металлу срезаны и спилены все мешающие части.

Raspberry Pi в картридже от NES - 5

С Raspberry Pi были спаяны выступающие разъемы. Знатоки говорят, что можно обойтись и без паяльной станции, если сначала аккуратненько разобрать разъемы кусачками, а потом выпаять по одной ножке. Всё наклеено на термоклей. Между разъемами USB и малинкой проложил изолятор из неплавящегося пластика. Не забывайте соединять GND Raspberry Pi и корпус USB разъема (на картинке выше не показано). Иначе некоторые джойстики не будут работать.

Raspberry Pi в картридже от NES - 6

На малинку был установлен последний Retropie. Поначалу стоял Recalbox, но я от него отказался, поскольку у него не поддерживается вибрация джойстиков на приставках Playstation 1. Но надо сказать, Recalbox чуть удобнее, в плане того, что работает из коробки и не надо ничего настраивать. В Retropie куча настроек, настраивать можно бесконечно. Этим он мне и понравился.
Вот что получилось. Подключаются любые джойстики с xinput.

Raspberry Pi в картридже от NES - 7

Экран

Аппетит приходит во время еды. Как насчет встроить экранчик в картридж? Для игры или вывода изображения обложки игры. Был заказан такой экран. Это 800*480 3,5 дюймовый экран с параллельным интерфейсом DPI, который использует почти все GPIO Raspberry Pi. У меня он работает в режиме 120 Hz (но рендер все равно в 60 Hz), отклик мгновенный. Единственный минус — это 6 битная матрица. Всего 262 144 цвета. Хотя, в общем-то, это особо не заметно, судите сами.

Raspberry Pi в картридже от NES - 8

Скриншот из игры Comix Zone (Кликабельно)

Все ножки с экрана и Raspberry Pi были спаяны. Экран был припаян двумя шлейфами с раздербаненного старенького кабеля IDE. Под экран установлены закладные в 5мм, он не касается нижней стенки картриджа. По периметру дисплея наклеена изолента, чтобы не было боковых засветов. Все приклеено на термоклей. На верхней крышке я прорезал окно и вклеил стекло толщиной 2мм.

Raspberry Pi в картридже от NES - 9

Для того, чтобы запустить вывод изображения на этот экран, надо поправить конфиг /boot/config.txt. Рекомендую для обладателей Windows программу WinSCP, которая соединяясь с Raspberry Pi по SSH, дает представление файлов как в Total commander'e. Очень удобно. Особенно, если запустить ее в режиме shell sudo su -, которая дает доступ ко всем файлам.

К сожалению, когда включен DPI экран, вывод видео по HDMI не работает. Поэтому я создал в папке /boot/ два конфига, один config_hdmi.txt, второй config_dpi.txt. В конфиге config_hdmi.txt выставлено разрешение 1080p60Hz и убран overscan. config_dpi.txt содержит настройки DPI экрана.

config_dpi.txt

# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1

disable_overscan=1

# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1

# Sound output. Set to 0 or comment for autodetect, 1 for DVI, 2 to force HDMI.
#hdmi_drive=2

# Using /etc/modules is deprecated and no longer supported on 4.4 kernel
# So manually enable audio
dtparam=audio=on

config_hdmi_boost=0

# force hdmi while the tv can take time before sending the signal on the hdmi output
hdmi_force_hotplug=1

# uncomment for composite PAL
#sdtv_mode=2

# uncomment for lirc-rpi
#dtoverlay=lirc-rpi

#3.5 HD tft screen 800x480
dtoverlay=dpi24
overscan_left=0
overscan_right=0
overscan_top=0
overscan_bottom=0

#Banggood
framebuffer_width=800
framebuffer_height=480
dtparam=spi=off
dtparam=i2c_arm=off
enable_dpi_lcd=1
display_default_lcd=1
dpi_output_format=0x6f015
dpi_group=2
dpi_mode=87
hdmi_timings=480 0 16 16 24 800 0 4 2 2 0 0 0 120 0 46080000 6
display_rotate=3


# if you plug your tv at the same time as your rpi and that the rpi switches from the hdmi or give a low resolution because tv had no enough time to initialize it
boot_delay=3

# uncomment if you don't want the rainbow at startup
#disable_splash=1

# default CEC name
#cec_osd_name=recalbox

dtparam=spi=off

# Overclock
gpu_mem_256=128
gpu_mem_512=256
gpu_mem_1024=256
overscan_scale=1
gpu_mem=256
start_x=0
enable_uart=0

avoid_safe_mode=1

kernel=zImage

config_hdmi.txt


# For more options and information see
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details

# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1

# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
disable_overscan=1

# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16

# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720

# uncomment if hdmi display is not detected and composite is being output
hdmi_force_hotplug=1

# uncomment to force a specific HDMI mode (this will force VGA)
hdmi_group=1

#1080p60fps
hdmi_mode=16

# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2

# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4

# uncomment for composite PAL
#sdtv_mode=2

#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800

# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
dtparam=spi=off

# Uncomment this to enable the lirc-rpi module
#dtoverlay=lirc-rpi

# Additional overlays and parameters are documented /boot/overlays/README

# Enable audio (loads snd_bcm2835)
dtparam=audio=on
gpu_mem_256=128
gpu_mem_512=256
gpu_mem_1024=256
overscan_scale=1
gpu_mem=256
start_x=0
enable_uart=0

Переключать конфиги будет наш автоскрипт который доступен по сети
\192.168.x.xxxconfigsallautostart.sh или в папке на устройстве /opt/retropie/configs/all/autostart.sh

autostart.sh

# Check to see if display is not connected
_NOHDMI=$(tvservice -n ) || true
# Check to make sure it's not already in LCD mode
_ISLCD=$(tvservice -s | grep "LCD") || true
# HDMI is connected - turn off backlight LCD
_HDMI=$(tvservice -s | grep "0x12000a") || true

if [ -z "$_NOHDMI" ]; then
  if [ "$_ISLCD" ]; then
    printf "NO HDMI connected, LCD DPI display config already activen"
    #do nothing
  else
    printf "NO HDMI connected, Switching to LCD DPI displayn"
    #change config to Hyperpixel and reboot since no display detected

    sudo cp /boot/config_dpi.txt /boot/config.txt
    sudo reboot now

  fi
elif [ "$_NOHDMI" ]; then
  if [ "$_ISLCD" ]; then
    printf "HDMI is connected, but LCD DPI config is being usedn"
    #we need to switch to HDMI display config and reboot

    sudo cp /boot/config_hdmi.txt /boot/config.txt
    sudo reboot now

  elif [ "$_HDMI" ]; then
    printf "HDMI is connected, HDMI config detected, so turning off LCD BLn"
    #we need to shut off the backlight on the Hyperpixel display since we aren't using it
    #don't panic, a reboot automatically resets this - it isn't a persistent value
    #also to do this the config.txt file needs to load the backlight module on startup
    #to control it even if you aren't loading the overlay driver for the display

    # this comment

    #echo 1 | sudo tee /sys/class/backlight/rpi_backlight/bl_power

  else
    #debugging catchall - shouldn't happen since we expect 0x12000a - but you never know...
    printf "HDMI is connected, HDMI config detected, your tv might not like 1920x1080 resolutionn"
  fi
else
  #do nothing - based on previous if statements - you either have HDMI or you don't have it...
  printf "Debug catchall point - sorry I can't help you out - I haven't run into the error state yet!n"
fi

emulationstation #auto

Также был написан скрипт switchscreen.sh, который надо положить в /home/pi/RetroPie/retropiemenu/. Этот скрипт переключает конфиги вручную и доступен из главного меню настроек Retropie. Надо после его запуска вытащить кабель HDMI, а то после перезагрузки всё переключится обратно автоматически. Не забудьте скрипту прописать

chmod +x /home/pi/RetroPie/retropiemenu/switchscreen.sh

switchscreen.sh

#!/bin/bash
# Check to see if display is dpi
_DPI=$(grep dpi /boot/config.txt) || true

if [ "$_DPI" ]; then
  printf "Switch to HDMIn"
  sudo cp /boot/config_hdmi.txt /boot/config.txt
  sudo reboot now

else
  printf "Switch to DPI LCDn"
  sudo cp /boot/config_dpi.txt /boot/config.txt
  sudo reboot now
fi
exit 0

В autostart.sh видны следы кода, отключающие подсветку DPI экрана, когда включен HDMI. Этот скрипт я скопипастил в интернете, так что на нашем экране это не работает. Можно было бы заморочиться с транзисторами, чтобы отключать питание экрана, но зачем, если нам надо выводить картинку обложки в данный момент запущенной игры. Надо только разобраться, что такое DPI.

Parallel Display Interface (DPI)

DPI, как было сказано, это параллельный интерфейс для экранов. Информации по этому интерфейсу раз, два и обчелся. Ну а теперь еще и здесь будет, на русском.

Все попытки включить DPI консольными командами во время работы HDMI результатов не дали. Возможно делал что-то не то. Был принят к реализации план Б: выводить изображение на малый экран, дергая программно за ножки GPIO.

DPI характеризуется тем, что один пиксель передается дисплею за один такт сигнала clock. Поскольку у нас матрица 6-битная, то это 18 выводов для трех цветов, а также присутствуют выводы display enable (обозначает валидную дату), h_sync (устанавливает нулевой адрес горизонтальной строки в контроллере дисплея), v_sync (устанавливает нулевой адрес вертикальной строки в контроллере дисплея). Защелкивание данных происходит по заднему фронту сигнала clock. Это известно, если расшифровать строчку «dpi_output_format=0x6f015» из нашего config_dpi.txt согласно этой терминологии.

dpi_output_format

output_format          = (dpi_output_format >>  0) & 0xf;
rgb_order              = (dpi_output_format >>  4) & 0xf;

output_enable_mode     = (dpi_output_format >>  8) & 0x1;
invert_pixel_clock     = (dpi_output_format >>  9) & 0x1;

hsync_disable          = (dpi_output_format >> 12) & 0x1;
vsync_disable          = (dpi_output_format >> 13) & 0x1;
output_enable_disable  = (dpi_output_format >> 14) & 0x1;

hsync_polarity         = (dpi_output_format >> 16) & 0x1;
vsync_polarity         = (dpi_output_format >> 17) & 0x1;
output_enable_polarity = (dpi_output_format >> 18) & 0x1;

hsync_phase            = (dpi_output_format >> 20) & 0x1;
vsync_phase            = (dpi_output_format >> 21) & 0x1;
output_enable_phase    = (dpi_output_format >> 22) & 0x1;

output_format:
   1: DPI_OUTPUT_FORMAT_9BIT_666
   2: DPI_OUTPUT_FORMAT_16BIT_565_CFG1
   3: DPI_OUTPUT_FORMAT_16BIT_565_CFG2
   4: DPI_OUTPUT_FORMAT_16BIT_565_CFG3
   5: DPI_OUTPUT_FORMAT_18BIT_666_CFG1
   6: DPI_OUTPUT_FORMAT_18BIT_666_CFG2
   7: DPI_OUTPUT_FORMAT_24BIT_888

rgb_order:
   1: DPI_RGB_ORDER_RGB
   2: DPI_RGB_ORDER_BGR
   3: DPI_RGB_ORDER_GRB
   4: DPI_RGB_ORDER_BRG

output_enable_mode:
   0: DPI_OUTPUT_ENABLE_MODE_DATA_VALID
   1: DPI_OUTPUT_ENABLE_MODE_COMBINED_SYNCS

invert_pixel_clock:
   0: RGB Data changes on rising edge and is stable at falling edge
   1: RGB Data changes on falling edge and is stable at rising edge.

hsync/vsync/output_enable_polarity:
   0: default for HDMI mode
   1: inverted

hsync/vsync/oe phases:
   0: DPI_PHASE_POSEDGE
   1: DPI_PHASE_NEGEDGE

Raspberry Pi в картридже от NES - 10

Последовательность битов приведена на рисунке выше. На каждую строчку, начинающуюся с VSYNC, приходится полный цикл тактов строчки HSYNC. Это на один кадр. Back и Front porch это так называемые отступы у дисплея, которые есть в памяти контроллера, но их нет на экране.

Теперь расшифруем строку «hdmi_timings=480 0 16 16 24 800 0 4 2 2 0 0 0 120 0 46080000 6» из нашего config_dpi.txt. Здесь ничего сложного нет, просто записываем параметры по порядку.

Raspberry Pi в картридже от NES - 11

Какие GPIO ноги используются для передачи цветов, показано на этой картинке. У нас Mode 5. Внимание, это не ноги по порядку, а именно обозначения GPIO! Остальные сигналы Clock — GPIO 0, DE — GPIO 1, VSYNC — GPIO 2, HSYNC — GPIO 3.

Raspberry Pi в картридже от NES - 12

Быстренько был установлен питон, необходимая GPIO библиотека и написан hello-скрипт хотя бы окрашивающий экран в синий цвет. А еще у меня был когнитивный диссонанс, когда Notepad++ на Windows не показывал отступы, там где они были в nano, при этом при переносе строк делал табуляцию, а не пробелы. Кстати, VSCode тем же самым грешит, как поправить, не нашел.

Python script

from gpiozero import LED
from time import sleep

sleep_time = 0.0

clock = LED(0)
de = LED(1)
vsync = LED(2)
hsync = LED(3)

red2 = LED(16)
red3 = LED(17)
red4 = LED(18)
red5 = LED(19)
red6 = LED(20)
red7 = LED(21)

green2 = LED(10)
green3 = LED(11)
green4 = LED(12)
green5 = LED(13)
green6 = LED(14)
green7 = LED(15)

blue2 = LED(4)
blue3 = LED(5)
blue4 = LED(6)
blue5 = LED(7)
blue6 = LED(8)
blue7 = LED(9)


def v_sync(frame):
    vsync.on()
    for n in range(frame):
        clock.on()
        #sleep(sleep_time)
        clock.off()
        #sleep(sleep_time)
        #print("vsync")
    vsync.off()
    pass

def h_sync(frame):
    hsync.on()
    for n in range(frame):
        clock.on()
        #sleep(sleep_time)
        clock.off()
        #sleep(sleep_time)
        #print("hsync")
    hsync.off()
    pass

def clc(frame):
    for n in range(frame):
        clock.on()
        #sleep(sleep_time)
        clock.off()
        #sleep(sleep_time)
    pass


red2.off()
red3.off()
red4.off()
red5.off()
red6.off()
red7.off()

green2.off()
green3.off()
green4.off()
green5.off()
green6.off()
green7.off()

blue2.on()
blue3.on()
blue4.on()
blue5.on()
blue6.on()
blue7.on()

clock.off()

de.off()
#de.on()

sleep(sleep_time)

v_sync(2)
clc(2)

for row in range(5):
    v_sync(2)
    # v_back_porch(2)
    clc(2)
    for column in range(800):
        h_sync(16)
        # h_back_porch(16)
        clc(16)
        # LCD column
        de.on()
        clc(480)
        de.off()
        # h_front_porch(24)
        clc(24)
    # v_front_porch(4)
    clc(4)
de.off()


red2.off()
red3.off()
red4.off()
red5.off()
red6.off()
red7.off()

green2.off()
green3.off()
green4.off()
green5.off()
green6.off()
green7.off()

blue2.off()
blue3.off()
blue4.off()
blue5.off()
blue6.off()
blue7.off()

Raspberry Pi в картридже от NES - 13

Слишком ме-е-едлено, Python. Для меня было неожиданностью то, что уже отрисованные пиксели исчезают. Хотя, чего я ждал, это же очевидно.

Принято решение переписать всё на С. Работает резвее, примерно несколько кадров в секунду. Экран рябит как на старых ЭЛТ мониторах или радарах. То что надо. Ретро! Код выложил на GitHub.

Raspberry Pi в картридже от NES - 14

Доступ к GPIO осуществляется напрямую, через регистры SoC чипа BCM2837. Примеры кода брал здесь.

Началось всё с совсем крохотной программки, но теперь на дисплей выводятся еще загрузка процессора и памяти в виде маленьких скролл-баров. Температура процессора рисуется вот таким шрифтом.

Raspberry Pi в картридже от NES - 15

Чтобы запустить код, надо скопировать содержимое репозитория в папку /home/pi/lcd_screen/ (Кто знает как на C под nix написать путь относительно бинарника, а не рабочей папки? Поэтому пока только в эту папку) и выполнить следующие команды.

gcc ./lcd_screen/lcd.c -o ./lcd_screen/lcd
chmod +x ./lcd_screen/lcd

Либо скачать сразу бинарник из релизов. Чтобы запустить, надо набрать следующее. SUDO требуется для доступа к GPIO.

sudo ./lcd_screen/lcd path/file.bmp usec_per_frame

Где «path/file.bmp» — путь до файла изображения, работает только с BMP форматом, «usec_per_frame» — задержка между кадрами в микросекундах, чтобы напрасно не грузить процессор.

Автоматизируем запуск нашей программки lcd, чтобы она выводила нужную обложку, когда игра запущена. Конечно же, для загрузки обложек в Retropie используется встроенный scrapер.
Установим конвертер изображений. Он будет конвертить все форматы в bmp, поддерживаемый программой. Заодно и изменять размер, чтобы изображения были на весь экран.

sudo apt-get install imagemagick

В директории /opt/retropie/configs/all/ создадим два файла: runcommand-onstart.sh и runcommand-onend.sh. Эти скрипты Retropie автоматически выполняет при загрузке/завершении любой игры. Не забудьте прописать chmod +x каждому файлу.

runcommand-onstart.sh

#!/bin/sh

system="$1"
emulator="$2"
romname="$3" #with path

#echo $system

# LCD programm here: 
#find current config: dpi or hdmi
_DPI=$(grep dpi /boot/config.txt) || true
if ! [ "$_DPI" ]; #if hdmi 
 then
  sudo killall lcd 
  # remove path
  filename=$(basename "$romname")
  # remove extension
  filename="${filename%.*}"
  # add image path
  file_png="/home/pi/.emulationstation/downloaded_images/$system/$filename-image.png"
  file_jpg="/home/pi/.emulationstation/downloaded_images/$system/$filename-image.jpg"
  #if system snes and n64 then rotate image 270 degree
  if [ "$system" = "snes" ] || [ "$system" = "n64" ]
  then
	if test -f "$file_png"; #fing file
	then  
		convert "$file_png" -resize '800x480' -type TrueColor -alpha Remove -rotate 270 /home/pi/lcd_screen/work.bmp
	elif test -f "$file_jpg"; 
	then 
		convert "$file_jpg" -resize '800x480' -type TrueColor -alpha Remove -rotate 270 /home/pi/lcd_screen/work.bmp 
	else
		convert "/opt/retropie/configs/$system/launching.png" -resize '480x800' -type TrueColor -alpha Remove -rotate 180 /home/pi/lcd_screen/work.bmp 	
	fi	
  else
  	if test -f "$file_png"; 
	then  
		convert "$file_png" -resize '480x800' -type TrueColor -alpha Remove -rotate 180 /home/pi/lcd_screen/work.bmp
	elif test -f "$file_jpg"; 
	then 
		convert "$file_jpg" -resize '480x800' -type TrueColor -alpha Remove -rotate 180 /home/pi/lcd_screen/work.bmp 
	else
		convert "/opt/retropie/configs/$system/launching.png" -resize '480x800' -type TrueColor -alpha Remove -rotate 180 /home/pi/lcd_screen/work.bmp 	
	fi	
  fi
  #launch my lcd project
  sudo /home/pi/lcd_screen/lcd /home/pi/lcd_screen/work.bmp 400000 &
 fi

runcommand-onend.sh

#!/bin/sh

_DPI=$(sudo grep dpi /boot/config.txt) || true
if ! [ "$_DPI" ]; 
then
  sudo killall lcd
  sudo /home/pi/lcd_screen/lcd /home/pi/lcd_screen/retropie.bmp 50000 &
#  cp /home/pi/lcd_screen/retropie.bmp /home/pi/lcd_screen/work.bmp
fi

В стартовом скрипте сначала проверяется наличие DPI соединения, затем ищется изображение с форматами jpeg или png, поворачивается на нужный угол, изменяется его размер и конвертится в формат bmp, потом запускается моя программа с необходимыми параметрами.

Охлаждение

Raspberry Pi 3B мощнее, чем Zero, и ему необходимо хорошее охлаждение. Особенно в таком закрытом корпусе. С небольшим радиатором, видимым на фото, через полчаса игры на любом эмуляторе температура ядра достигала 80 градусов и начинался тротлинг.

Raspberry Pi в картридже от NES - 16

Был заказан центробежный вентилятор 40*30*10 мм, но пока он не приехал, я просто попробовал выпилить из 3 мм алюминия небольшую пластину, размером 80*30 мм. К тому времени все пины GPIO я выпаял, поэтому они уже не мешались установке пластины. Дополнительно еще выпилил кусочек 20*10мм для контакта с чипом и сделал из пластин бутерброд. Это превзошло все мои ожидания, максимум 65 градусов на ядре.

Raspberry Pi в картридже от NES - 17

Так это выглядит внутри.

Raspberry Pi в картридже от NES - 18

В итоге что

Как это играется? Отлично! С криками, битьем геймпадов, взаимными упреками. Прямо как когда-то.

Никаких задержек и лагов замечено не было.

Экранчик, конечно, маловат, всего три с половиной дюйма. Разбаловали нас смартфоны с пятью дюймами, но играть можно. Текст читается, даже мелкий. Предпочитаю HDMI.

Можно прийти к другу, поиграть, портативность позволяет. Сопутствующие аксессуары: шлейфы, кабели, джойстики, зарядка занимают больше места, чем сама приставка.

Звук

К сожалению, штатный звук Raspberry Pi оставляет желать лучшего. В качестве звуковой системы применена ШИМ модуляция с пассивной фильтрацией. Поэтому был закуплен USB ЦАП на PCM2704. Главным образом, из-за своих размеров.

Очень не хватает вывода звука при игре на маленьком LCD экранчике, поэтому куплен также микроусилитель 3W на NS8002 и подобран динамик от планшета на 8 Ом.

USB ЦАП и NS8002

Raspberry Pi в картридже от NES - 19

Raspberry Pi в картридже от NES - 20

Всё это поместится под LCD экраном. Приедет, буду ставить.

Подпиливаем Retropie

Сборка окончена. Далее приведу некоторые менее интересные для развлекательного чтения особенности настроек Retropie.

Шейдеры

Большинство приставок, которые способен эмулировать Raspberry Pi, выдает разрешение 320x240 пикселей. По сегодняшним меркам это очень мало. Все игры приобретают ярко выраженную пикселизацию на современных экранах.

Raspberry Pi в картридже от NES - 21

Создатели Retroarch, который входит в состав Retropie, озаботились этим вопросом и добавили поддержку шейдеров. Например, мне очень нравится предустановленный xbr-lv1-noblend.glslp. Он, буквально, вытягивает детали из картинки. См. ниже.

Raspberry Pi в картридже от NES - 22

Скриншот из игры Castlevania: Symphony of the Night, советую в нее сыграть

Чтобы установить шейдер, зайдите в меню Retropie -> Configuration editor. Выберите Configure basic libretro emulator options, после выберите Configure default options for all libretro emulators. Затем установите Video Shader Enable в «true» и Video Shader File на желаемый шейдер. Установите также Video Smoth в «false», поскольку он только смазывает картинку. Можно даже выбрать что-то типа scanline шейдера, который эмитирует работу CRT телевизоров. Но это на любителя.

Raspberry Pi в картридже от NES - 23

Отрисовка шейдеров довольно затратная операция. При разрешении равном и выше 720p на RPi 3B появляются довольно заметные подлагивания. Поэтому в этом же меню выберите Render resolution «800x600». Не волнуйтесь, если вы до этого делали изменения в файле /boot/config.txt, как в этой статье выше чуть выше, то разрешение экрана по кабелю HDMI будет 1080p, но эмулятор будет рендерить картинку в 800x600 и растягивать на весь экран. И делает он это не плохо. По крайне мере, с шейдером лучше, чем без него, да и рендер в 1080p бесполезен, поскольку видеоданные игры всё равно нарисованы для разрешения 320x240.

Настройка джойстиков

Если у вас есть любой xinput геймпад (стандарт Micro$oft), он подойдет. Настраивается он при первом же запуске Retropie, либо через кнопку старт — Configure Input. Но и тут есть головная боль. Ушлые заокеанские ребята, чтобы не попадать на патентные судебные иски поменяли местами кнопки с A и B, X и Y.

Raspberry Pi в картридже от NES - 24

Если у вас геймпад от xbox или аналогичный, то настраивать надо с перевернутыми кнопками, как на NES. Затем зайти в Retropie -> Retropie Setup, выбрать Configuration / tools, затем emulationstation, поставить в Swap A/B Buttons in ES «Swapped». Потом заново переконфигурируйте джойстик.

Также, мне не нравится, как разработчики Retropie распорядились кнопочным фондом. Где комбинация кнопок сделать скриншот? Зачем мне кнопка reset, если я на нее попадаю каждый раз? Где кнопки перемотки и ускорения времени?

Чтобы это исправить, нужно подредактировать файл с названием вашего джойстика в /opt/retropie/configs/all/retroarch-joypads/. Также он доступен по сети \192.168.x.xxxconfigsallretroarch-joypads. После каждого обновления Retropie через апдейтер, нумерация привязки слетает, поэтому я не буду выкладывать весь конфиг. Напишу, что изменил лишь эти кнопки. Они выполняются при нажатии одновременно с Hotkey-м, обычно это кнопка с логотипом, посередине джойстика.

Button config

input_screenshot_btn = "0"
input_rewind_btn = "h0left"
input_hold_fast_forward_btn = "h0right"
input_state_slot_increase_btn = "h0up"
input_state_slot_decrease_btn = "h0down"

Здесь кнопка скриншотов назначена вместо reset. Fast forvard и rewind (перемотка назад) настроены на кнопки крестовины: вперед и назад. Кнопки крестовины вверх и вниз изменяют слот сохранения.

Rewind надо включить в конфиге /opt/retropie/configs/all/retroarch.cfg. Только не включайте Rewind на эмуляторе psx, всё начинает дико тормозить. Перемотка назад, по-умолчанию, отключена в конфиге psx.

Еще хочется добавить про Bluetooth. Сам я беспроводные джойстики не люблю и играю всегда с кабелем. Старая школа еще. Для любителей беспроводных джойстиков надо приобрести Bluetooth донгл и вставить в USB порт. Так будет лучше и никаких проблем не будет. Сам я не проверял, но знающие люди пишут.

Xboxdrv

Но и это еще не всё. В Retropie Setup в менеджере пакетов можно поставить различные порты, например Openttd, Doom или вообще DOS эмулятор Dosbox. Но управлять в них джойстиком не получится. Только клавиатурой и мышкой. Чтобы это исправить, нужно поставить в менеджере пакетов драйвер xboxdrv, который умеет эмулировать нажатия клавиатуры. Просто поставить из исходников, автозапуск делать не нужно, он не подходит под все джойстики.

Скрипт запуска напишем сами под наш геймпад. Добавим в /opt/retropie/configs/all/runcommand-onstart.sh следующие строки в конец файла.

runcommand-onstart.sh

# xboxdrv
sudo killall > /dev/null 2>&1 xboxdrv
if [ "$1" = "pc" ] || [ "$1" = "openttd" ] || [ "$1" = "doom" ] || [ "$1" = "kodi" ];
then
sudo /opt/retropie/supplementary/xboxdrv/bin/xboxdrv > /dev/shm/runcommand.log 2>&1 
    --evdev /dev/input/event0 
	--silent 
	--detach-kernel-driver 
	--force-feedback 
	--mimic-xpad 
	--trigger-as-button 
	--evdev-no-grab 
	--evdev-absmap ABS_X=x1,ABS_Y=y1,ABS_RX=x2,ABS_RY=y2,ABS_HAT0X=dpad_x,ABS_HAT0Y=dpad_y 
	--evdev-keymap KEY_#304=a,KEY_#305=b,KEY_#307=x,KEY_#308=y,KEY_#312=lt,KEY_#313=rt,KEY_#310=lb,KEY_#311=rb,KEY_#317=tl,KEY_#318=tr,KEY_#314=back,KEY_#315=start,KEY_#316=guide 
	--axismap -Y1^deadzone:3000=Y1,-Y2^deadzone:3000=Y2 
	--ui-axismap x2^deadzone:3000=KEY_LEFT:KEY_RIGHT,y2=KEY_UP:KEY_DOWN 
	--ui-axismap x1^deadzone:3000=REL_X:06,y1=REL_Y:06 
	--ui-axismap dpad_x^deadzone:0=KEY_LEFT:KEY_RIGHT,dpad_y^deadzone:0=KEY_UP:KEY_DOWN 
	--ui-buttonmap rt=BTN_LEFT,lt=BTN_RIGHT,start=KEY_ENTER,back=KEY_ESC,tl=KEY_4,tr=KEY_5,lb=KEY_2,rb=KEY_3,a=KEY_SPACE,b=KEY_M,x=KEY_3,y=KEY_LEFTCTRL,guide=KEY_Y 
&
fi

Здесь $1 — наша целевая система, при которой запускается xboxdrv. Можно добавлять по аналогии. Строки --evdev-absmap --evdev-keymap отвечают за привязку осей и кнопок к вашему джойстику. Скрипт выше дан для контроллера Xbox One S. Чтобы узнать какая ось и кнопка соответствуют номеру или названию вашего джойстика, нужно в консоли набрать команду evtest. Заодно можно посмотреть какой event соответствует нашему джойстику. У меня это /dev/input/event0 который стоит в параметре --evdev.

Параметры --ui-axismap эмулируют оси мыши, а --ui-buttonmap кнопки клавиатуры. В данном примере курки — это кнопки мыши, левый стик — мышь, правый стик — курсорные клавиши. Старт, селект — enter и esc, соответственно. На остальные кнопки привязаны цифры клавиатуры. Задействовать крестовину под кнопки клавиатуры, к сожалению, не удалось. Почему-то на джойстике Xbox One S отказывается работать.

С таким конфигом отлично играются стратегии, наподобие Theme Hospital, OpenTTD и пр. Чуть хуже играется в шутеры, но вы можете создать аналогичные скрипты запуска под шутеры в этом же файле, меняя там параметр $1.

Чтобы обеспечить нормальную работу джойстика в emulationstation, нужно завершить xboxdrv после выхода из игры. Для этого в конец файла /opt/retropie/configs/all/runcommand-onend.sh добавляем следующее.

runcommand-onend.sh

sudo killall > /dev/null 2>&1 xboxdrv

Если при обновлении Retropie что-то пошло не так

Однажды, я запустил обновление Retropie и при распаковке ядра отвалился встроенный Wi-Fi. Устройство загружалось, но не реагировало ни на какие кнопки, в том числе на подключенной клавиатуре. SSH нет, так как нет Wi-Fi, на клавиатуру не реагирует, а SD карточку не достать…

Заметил, что клавиатура работает при загрузке. Понажимал много раз ctrl+c и, о, консоль! Но как теперь восстановить Wi-Fi? Интерфейс wlan0 отсутствовал от слова совсем. Запуск апдейтера не помог, поскольку он подтягивает файлы с интернета.

Первым делом в /opt/retropie/configs/all/autostart.sh закомментировал запуск emulationstation и перезагрузился. После перезапуска загружается консоль, клавиатура работает. Дальнейшее гугление, как вернуть wlan дало вот это. Команда переконфигурирует все установленные пакеты. Помогло.

sudo dpkg --configure -a

Чтобы Retropie выглядел не как Linux станция

При загрузке приставки мне не хочется смотреть на лог загрузки Linux. Он портит весь дух приставок девяностых.

Чтобы убрать лог загрузки Linux

Чтобы убрать лог загрузки Linux, нужно привести файл /boot/cmdline.txt к такому виду. Всё в одну строку.

cmdline.txt

dwc_otg.lpm_enable=0 console=tty3 root=PARTUUID=f2d3cb4f-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait loglevel=3 consoleblank=0 plymouth.enable=0 quiet vt.global_cursor_default=0 plymouth.enable=0 plymouth.ignore-serial-consoles splash

Кратко, конфиг убирает лого, выводит сообщения в другую консоль, убирает мигающий курсор.
Затем убираем весь текст в motd.

nano /etc/motd

Убираем автологин текст.

sudo nano /etc/systemd/system/autologin@.service

Нужно в этом файле изменить строку

ExecStart=-/sbin/agetty --autologin pi --noclear %I $TERM

На

ExecStart=-/sbin/agetty --skip-login --noclear --noissue --login-options "-f pi" %I $TERM

Более подробно про это написано здесь.

Также, при загрузке системы можно вывести свое фото — splashscreen. Можно и несколько, они будут сменять друг друга со временем. Нужно положить свои картинки в папку в сети \192.168.x.xxxsplashscreens, и выбрать их в меню Retropie -> SPLASH SCREEN -> Append Splashscreen to list.
Мне, например, безумно нравится вот эта картинка.

Raspberry Pi в картридже от NES - 25

Также в Retropie установлен runcommand, который при запуске игры выводит консольный обрезок с предложением нажатия клавиши. Этот экран можно заменить на милые картиночки игровых приставок.

Raspberry Pi в картридже от NES - 26

Подробная инструкция, как это сделать, написана здесь.

Что еще можно сделать

Улучшать можно бесконечно. Приведу еще пару ссылок, что можно сделать. Пишите еще интересные штуки, которые можно добавить. Спасибо за внимание.

Он того стоит.

Автор: 8street

Источник

* - обязательные к заполнению поля