Este artículo va de otra consola de juegos portátil casera a modo de continuación de la primera que desarrollé (http://bit.ly/2yFj4th). En mi primer desarrollo, utilicé un ODROID-W (clon de pi) y una carcasa GameBoy nueva. Para este nuevo proyecto, deseaba algo más potente para ejecutar juegos de N64, Dreamcast y PSX, y también algún que otro juego nativo de Linux. No hay muchas opciones de bajo consumo con suficiente CPU + GPU para esto, así que elegí un ODROID-C0. Además, en lugar de usar y transformar una carcasa existente, utilicé una impresión 3D diseñada por mí con un tamaño y unas dimensiones muy optimizadas. Quisiera dar las gracias a la comunidad ODROID (forum.ODROID.com) y en particular a @meveric por su distribución debian y los paquetes optimizados para ODROID.
Componentes
Aquí tienes una lista de todos los componentes que utilice en este desarrollo:
Componentes principales:
- ODROID-C0
- Módulo eMMC de 8GB
- MicroSD XC de 128 Gb (SanDisk Ultra, XC I, clase 10)
- Pantalla TFT NTSC/PAL de 3.5" (http://bit.ly/2yUyXgd)
- Una Placa PCB prototipo de 4x6cm
Componentes para el Audio:
- Amplificador de audio estéreo 2.8W clase D
- 2 altavoces PSP 2000/3000
- Una tarjeta de sonido USB barata con un pequeño cable USB
Componentes para la Batería:
- 2 baterías de LiPo: Keeppower 16650 3.7v 2500mA con protección
- 2 conectores MOLEX, 50079-8100
- 2 receptáculos MOLEX, 51021-0200
Componentes para los Controles:
- 12 Pulsadores táctiles de 8 mm (http://bit.ly/2xN8qDW)
- 4 Botones Interruptores táctiles de 6 mm (http://bit.ly/2xNmlcU)
- 2 Sticks analógicos PSP 1000
- 1 Multiplexor analógico MC14051BCL
Componentes para la Refrigeración
- 2 Disipadores de calor de cobre PS3 GPU
- 4 disipadores de calor de cobre de 15x15mm
- Un poco de relleno térmico de 1 mm
- Un poco de Pasta Térmica de Silicio
Otros Componentes Electrónicos:
- Un led azul de 3 mm
- Unos cuantos alambres de un viejo cable plano IDE
- Algunos cables de conexión de placa
- 3 Resistencias
Componentes para Adornar:
- Plantillas de esmalte de uñas para los colores (negro, amarillo, rojo, verde, azul)
- Papel de lija 200, 600 y 1200
- XTC 3D (http://bit.ly/2fG3l5O)
- Pintura en espray satinada blanca
Consumo de energía previsto
Las fuentes principales de consumo de energía son el ODROID-C0, la pantalla y el sistema de audio (tarjeta de sonido y amplificador de audio). Antes de empezar, decidí medir el consumo de estos 3 componentes:
- ODROID-C0: 200-400 mAh dependiendo del uso de la CPU y de la GPU
- Sistema de audio: 310 mAh
- Pantalla: 420 mAh
Hace un total de 1130 mAh a 5v, de modo que son 5650mA/hora. Las baterías que usé son de (al menos) 3.7v x 5000 mA con un total de 18500 mA. La consola debería durar más de 3h en todos los casos.
¿Por qué usar una pantalla con tan poca resolución?
Existen varios motivos para ello: baja potencia, 60 FPS, cableado sencillo y tiene poca definición aparentando un televisor antiguo, lo que hace que el suavizado de bordes por hardware sea muy bueno.
¿Por qué usar baterias en forma de cilindro? Se trata de una cuestión de optimización del espacio en relación a la capacidad que quería. Usar una batería plana más clásica me habría obligado a ampliar la profundidad de la carcasa en más de 2 cm, aunque esa fue mi primera intención.
¿Por qué usar una placa prototipo para montar los componentes adicionales?
El objetivo era montar con facilidad todos los componentes como si fueran una única placa base, y realmente puedo decir que resulto muy útil.
¿Por qué es necesario un multiplexor analógico?
El ODROID-C0 solo proporciona 2 entradas analógicas, y una ya se usa para informar del nivel de batería. Por lo tanto, solo había 1 entrada analógica disponible para un total de 4 ejes analógicos (2 sticks con 2 direcciones cada uno). La única forma de leer los 4 ejes analógicos con una sola entrada analógica era con un multiplexor. Afortunadamente, el ODROID-C0 tiene suficientes pins digitales para usar 2 de ellos y así poder alternar los canales analógicos.
¿Por qué usar un módulo eMMC en lugar de una microSD?
El módulo eMMC es mucho más rápido que una microSD. Permite que la consola se inicie en unos pocos segundos incluso con Xorg, un gestor de ventanas, y Emulation Station con muchos juegos. Utilizo el eMMC para el sistema operativo y la microSD para los juegos y las vistas previas de los videos.
Carcasa impresa en 3D
La carcasa de la consola se ha modelado con Freecad. La diseñé específicamente para este proyecto, con un tamaño muy concreto para la placa base y todos los componentes. Fue mi primer modelo 3D y la primera impresión 3D, así que puede tener errores. No obstante, los archivos Freecad están disponibles en GitHub (http://bit.ly/2fGJWRU) y los archivos STL están distribuidos libremente en Thingverse en (http://bit.ly/2xW9FAh).
La carcasa es muy similar a una Nintendo DS. Puede que no sea tan evidente, pero usar las dimensiones de una consola tan conocida me permitió encontrar fundas de protección buenas y baratas. Como podrás ver en las fotos de más adelante, utilicé una funda NDS para proteger mi GamODROID-C0, que encontré por unos pocos euros.
Para conseguir un buen acabado, primero utilicé el papel de lija 600 y 1200 en todas las piezas. Luego, usé un producto llamado XTC-3D. Es asombroso y ofrece un aspecto brillante, pero todavía no tenía el acabado que perseguía. Utilicé de nuevo el papel de lija 1200 antes de usar una pintura satinada blanca. Finalmente, esto me dio el acabado que ves en las fotos.
Para las piezas más pequeñas como botones y el D-pad, utilicé un poco de esmalte de uñas. Es muy barato y realmente proporciona un acabado genial. Para finalizar barnicé los botones y el D-pad con un barniz de uñas transparente para proteger los colores, ya que éstos son muy utilizados en la consola.
Mi objetivo era desarrollar una placa base de una única pieza para hacerla más robusta y fácil de colocar dentro de la carcasa. También desarrollé pequeñas placas para los botones Inicio/selección y el D-pad.
Montar la pantalla
El sistema es aproximadamente el mismo que el que use para mi consola Retroboy (http://bit.ly/2yFj4th). Sin embargo, existen algunas diferencias en lo que respecta al conector: V-in y la salida compuesta han sido invertidas esta vez. La figura 5 muestra la pantalla original, tal como se encuentra en el sitio web de Adafruit.
Primero retiré el conector blanco, conecté el V-in directamente a la salida del regulador de voltaje y añadí dos cables para llevar la alimentación a través de uno de los pins ODROID 5V, como se muestra en la Figura 6.
Tarjeta de sonido
Elegí una tarjeta de sonido USB barata que tuviera un cable entre la placa y el conector USB. Esto era importante porque así resultaba más fácil retirar la soldadura.
Empecé a desmontar los cables, los conectores y volví a perforar los agujeros. Preparé la placa ODROID añadiendo los pins al primer conector USB, tal y como se muestra en las Figuras 8 y 9. Finalmente, soldé la tarjeta de sonido directamente a los pins, como se muestra en la Figura 10.
Placa de ampliación con puerto USB
Puse la placa de ampliación justo debajo de la tarjeta de sonido USB. Primero soldé un conector USB, luego lo conecté al segundo conector USB del ODROID a través de la placa de ampliación. Ten en cuenta que también soldé la placa de ampliación a la placa base ODROID para hacer que todo fuese más robusto.
Completando el sistema de audio en la placa de ampliación
Tener una tarjeta de sonido con salida analógica puede dar un buen resultado, pero es mejor una toma de audio 3.5 y un buen amplificador para montar los altavoces. Ese fue precisamente el siguiente paso: cablear y soldar los componentes en la placa de ampliación.
Cableado del multiplexor analógico
La soldadura de esta pequeña pieza supuso añadir muchos cables y terminó cubriendo casi toda la placa de ampliación. Tuve que usar lo siguiente: Vdd (Vin), Vss (tierra), x (salida analógica), x0, x1, x2, x3 (entradas analógicas), A, B (interruptores digitales). C no era necesario ya que 2 interruptores eran suficientes para alternar entre las primeras 4 salidas. Vee y INH fueron conectados a tierra. Ten presente que hice una separación de voltaje entre x (salida) y la entrada analógica del ODROID. Esto se debe a que los sticks analógicos PSP y MC14051B funcionan en 5V, mientras que la entrada analógica del ODROID-C0 acepta un máximo de 1.8v.
Botones del volumen
Es posible que hayas visto en la foto anterior que hay 2 botones pulsadores en uno de los bordes de la placa de ampliación. Los conecté a los pins GPIO para controlar el volumen del audio, tal y como se muestra en la Figura 20..
Botones de inicio/selección
Utilicé botones pulsadores para los botones de inicio y selección. Los monté en una pequeña placa adicional junto con un led azul para monitorizar la batería.
Baterías
Como he indicado anteriormente, he utilizado un par de baterías LiPo cilíndricas con protección. Las conecté en paralelo para conseguir 5000 mA. Tuve que soldar unos cables directamente a las baterías y añadir un conector Molex para poder conectar las dos baterías al conector LiPo del ODROID-C0.
Montaje de los componentes
Llegado a este punto, ya tenía todo lo relacionado con el hardware. Comencé a montar en la parte frontal de la carcasa la pantalla, los sticks analógicos, el D-pad, las placas a-b-x-y y los botones L1 + R1. La pantalla no está pegada, sino que se mantiene con dos barrotes transversales. Como puedes ver en la Figura 23, estas varillas me permitieron colocar y reconducir todos los cables.
El siguiente paso a realizar en la parte frontal de la carcasa es añadir los altavoces, los botones de inicio/selección y cablear todo con una puesta a tierra común. Los pasos finales antes del cierre son añadir un disipador de calor, colocar los botones L2 + R2 y la placa base en la parte posterior de la carcasa, luego soldar todo a GPIO. Ten en cuenta también el cable amarillo que es la salida compuesta del ODROID que va a la entrada 1 de la pantalla.
Software
Desarrollé un script que configura el 80% del sistema, incluida una copia de los archivos de configuración específicos. El otro 20% es para la ROMs y los ajustes personales. Si alguien quiere hacer lo mismo, el script es bastante fácil de adaptar y volver a ejecutar.
Antes de empezar a comentar el script de instalación, aquí te dejo los pasos de instalación que lleve a cabo:
- Implementación de la imagen mínima Debian Jessie de @meveric en el módulo eMMC (http://bit.ly/2yF2PML)
- Se crearon dos particiones en la microSD de 128GB: 4 Gb para guardar los estados y el resto para las ROMs, las cuales estarán montadas en /mnt/states y /mnt/ressources). Hice 2 particiones porque tenía la intención de crear un sistema de solo lectura a excepción de los estados, pero finalmente mantuve un sistema completo de lectura/escritura.
- Se creó una carpeta GameODROID en /root y se copia el script de instalación y sus dependencias.
Script de Instalacíon
El script de instalación y todas las dependencias las puedes encontrar en GitHub en http://bit.ly/2fGJWRU. Está organizado con funciones dedicadas para cada paso.
La primera función crea puntos de montaje personalizados, copia el fstab personalizado y activa tmpfs:
function fstab { echo "fstab and filesystem" mkdir -p /mnt/states mkdir -p /mnt/ressources cp /root/GameODROID/fstab /etc/fstab sed -i "s/#RAMLOCK=yes/RAMLOCK=yes/" /etc/default/tmpfs sed -i "s/#RAMSHM=yes/RAMSHM=yes/" /etc/default/tmpfs }El archivo fstab personalizado permite cambiar las opciones de montaje para optimizar la velocidad (noatime, discard) y usar una pequeña partición tmpfs para /var/log:
tmpfs /var/log tmpfs nodev,nosuid,noatime,size=20M 0 0 Tras esta primera función, el sistema se reinicia, luego se actualiza y se vuelve a reinicia: function uptodate
{ echo "update" apt-get update apt-get upgrade apt-get dist-upgrade }El paso final de esta fase es instalar todos los paquetes base necesarios (paquetes de funciones). No tiene nada de especial excepto dos cosas:
- evilwm : Tuve que usar un gestor de ventanas porque algunos juegos nativos no pueden detectar la resolución de pantalla nativa sin él. Descubrí que evilwm era muy buen candidato para la consola, ya que es muy ligero y casi invisible con las configuraciones por defecto.
- Antimicro-ODROID : es un software muy bueno que no conocía. Me permite asignar cualquier evento de teclado y ratón al joypad.
- Paquete de Python evdev: utilizado para configurar la entrada reicast
- Utilicé un archivo de configuración xorg específico para ODROID C1/C0 proporcionado por (http://bit.ly/2xaSonP)
Juegos
Esta parte corresponde a las funciones "emulators", "emulators_glupen64_meveric" y “nativegames”. Excepto para los juegos de Dreamcast para los que utilicé Reicase, el resto de emuladores son parte de Retroarch:
- pcsx-rearmed (PSX)
- fbalpha (CPS2)
- gambatte (Gameboy color)
- gpsp (Gameboy advance)
- mednafen-pce-fast (Pc-Engine + Cdrom)
- nestopia (Nes)
- picodrive (Sega 32X, SegaCD)
- pocketnes (Snes)
- genesis-plus-gx (GameGear, Genesis, MasterSystem)
- mednafen-ngp (Neogeo pocket color)
Para los juegos nativos, seleccioné aquellos que fueran divertidos para jugar con un gamepad y funcionaran correctamente en el ODROID-C0 con una pantalla pequeña:
- hurrican
- hcraft
- frogatto
- SuperMario War
- astromenace
- neverball
- shmupacabra
- aquaria
- Revolt
- Open JK3
- openjazz
- supertuxkart
- mars
- puzzlemoppet
- opentyrian
- pushover
Lanzador de juegos
Esto corresponde a la función "userinterface". Inicialmente, quería usar el modo Attract. Lamentablemente, la implementación de GLES en ODROID-C0/C1 no parece incluir las funciones glBlendEquationSeparateOES () y glBlendFuncSeparateOES (), que son obligatorias para compilar libFSML, que a su vez es obligatorio para compilar el modo Attract. De modo que, utilicé la última versión de Emulation Station con soporte de vista previa de video. Como quería cambiar la pantalla de inicio por defecto por una personalizada, tuve que reemplazar el archivo "splash_svg.cpp" en "EmulationStation/data/converted". Este archivo es una simple matriz C que contiene los bytes de un archivo SVG. Al margen de la configuración clásica de los sistemas, creé una específica que incluye dos scripts para cambiar la pantalla: pantalla interna o HDMI (consulta los scripts composite.sh y hdmi.sh).
Herramientas específicas
Esto corresponde a la función "localtools". Ésta se utilza principalmente para manejar el gamepad GPIO personalizado. Tuve que escribir un pequeño programa en C que crea un gamepad mediante el sondeo GPIO y la entrada de Linux para generar eventos. Utilicé el sondeo en lugar del IRQ porque el SoC no tiene suficiente IRQ para manejar todos los botones. Llamé a esta herramienta gpio_joypad y el código fuente está en GitHub en http://bit.ly/2xaTdgp. También maneja el multiplexor analógico para recuperar los valores de izquierda y derecha del sticks analógico.
Archivo de configuración de arranque
Esto corresponde a la función "bootini". Esta función consiste en copiar un archivo boot.ini personalizado en la partición de arranque. Los cambios importantes que hice son:
- Mantener súnicamente dos modos de video: cvbs480 (activado por defecto) y vga (comentado)
- Cec y vpu desactivados
- Argumentos del kernel modificados:
- “cvbsmode=480cvbs” para lograr una resolución NTSC de 60Hz en lugar de 50Hz PAL
- “max_freq=1824” para aumentar la frecuencia del reloj del SoC (necesario para los emuladores N64 y Dreamcast)
- “quiet loglevel=3 rd.systemd.show_status=false udev.log-priority=3” para que el arranque sea lo más silencioso posible
Inicialmente, quería mostrar la pantalla de inicio durante el proceso de arranque. Está bien explicado cómo hacerlo en el wiki de ODROID, pero desafortunadamente sólo funciona para resoluciones 720p.
Lanzar todo en el inicio
Esto corresponde a la función "startup". El inicio automático de X y Emulationstation en el arranque consistia en un servicio tty1 personalizado en systemd que lanza agetty con autologin, un perfil BASH que inicia X cuando la variable tty = tty1 y finalmente un xinitrc que inicia el gestor de ventanas y Emulation Station.
/etc/systemd/system/getty@tty1.service.d/override.conf
[Service] ExecStart= ExecStart=-/sbin/agetty --autologin root --noclear %I $TERM The bash /root/.profile : # ~/.profile: executed by Bourne-compatible login shells. if [ "$BASH" ]; then if [ -f ~/.bashrc ]; then . ~/.bashrc fi fi if [ "$(tty)" = "/dev/tty1" ] ; then /usr/local/bin/battery.sh & /usr/local/bin/gpio-joypad & startx -- -nocursor 2>&1 & fi mesg n/root/.xinitrc
# a WM is needed some software are correctly sized in full screen # e.g : emulationstation, rvgl evilwm & pid=$! emulationstation.sh & # this allows not to shutdown X when emulation is killed # We want that because we have to kill it after gamelaunch # else it does not reappear on screen (SDL_Createwindow() does never end) wait $pid Note that the bash profile start the joypad driver (gpio_joypad) and the battery monitoring script (battery.sh) before starting X. The battery monitoring script is not very accurate, but I dit not found any way to make a better monitoring to switch on the led on low battery or when charging: #!/bin/bash PIN=75 GPIO=/sys/class/gpio ACCESS=$GPIO/gpio$PIN LOWBAT=780 CHARGING=1020 if [ ! -d $ACCESS ] ; then echo $PIN > $GPIO/export echo out > $ACCESS/direction echo 0 > $ACCESS/value fi while true do ADCVAL=$(cat /sys/class/saradc/saradc_ch0) # echo "value : $ADCVAL" # charging if [ $ADCVAL -gt $CHARGING ]; then echo 1 > $ACCESS/value else # low bat if [ $ADCVAL -lt $LOWBAT ]; then echo 1 > $ACCESS/value sleep 1 echo 0 > $ACCESS/value else echo 0 > $ACCESS/value fi fi sleep 2 done
Finalizar y limpiar
Esto corresponde a la función "optimize_system". En esta función, el mensaje de inicio de sesión BASH está oculto (para que el proceso de arranque sea lo más silencioso posible) y se limpie la caché de los paquetes (apt-get clean). También se utilizan dos archivos de configuración. El journald.conf personalizado está aquí para escribir registros logs en la ram en lugar de en el disco para mejorar rendimiento:
[Journal] Storage=volatile I also created a specific alsa configuration file to add latency and buffers, so most sound stutering are avoided for n64 and dreamcast games: pcm.!default { type plug slave.pcm "softvol" ttable.0.1 0.8 ttable.1.0 0.8 } pcm.dmixer { type dmix ipc_key 1024 slave { pcm "hw:1,0" period_time 0 period_size 2048 buffer_size 65536 rate 44100 } bindings { 0 0 1 1 } } pcm.dsnooper { type dsnoop ipc_key 1024 slave { pcm "hw:1,0" channels 2 period_time 0 period_size 2048 buffer_size 65536 rate 44100 } bindings { 0 0 1 1 } } pcm.softvol { type softvol slave { pcm "dmixer" } control { name "Master" card 1 } } ctl.!default { type hw card 1 } ctl.softvol { type hw card 1 } ctl.dmixer { type hw card 1 }
Configuración general de Retroarch
Al margen de cambiar los botones y la ruta, tuve que adaptar algunos parámetros de videos de retroarch (root /.config/retroarch/retroarch.cfg) para optimizar el rendimiento y adaptar mejor al hardware:
video_refresh_rate = "59.950001" video_monitor_index = "0" video_fullscreen_x = "720" video_fullscreen_y = "480" video_vsync = "true" video_threaded = "true" video_force_aspect = "true"
Configuración específica del núcleo
También hice algunos ajustes en uno de los núcleos de emulador:
Permitiendo 6 botones para SegaCD y 32X:
picodrive_input1 = "6 button pad" Changing glupen64 parameters to optimize rendering on the ODROID SoC: glupen64-cpucore = "dynamic_recompiler" glupen64-rspmode = "HLE" glupen64-43screensize = "320x240" glupen64-BilinearMode = "standard" Allowing PSX analog joypad support: pcsx_rearmed_pad1type = "analog"Para el emulador Dreamcast, utilicé reicast-joyconfig (http://bit.ly/2fLE1yH) para generar la configuración del gamepad y copié el archivo resultante en /root/.config/reicast/joy.conf. También cambié la resolución de toda la pantalla para adaptarla a la pantalla CVBS:
[x11] fullscreen = 1 height = 480 width = 720
Asignaciones de teclado y ratón para juegos nativos
Algunos juegos nativos funcionan muy bien, pero requieren de un ratón o un teclado para algunas teclas especiales como Esc, Enter, Space, Shift y las teclas de flechas. Para asignar estas teclas a la consola de gamepad, yo utilicé antimicro. Es un programa sencillo que te permite asignar cualquier tecla del ratón y del teclado a cualquier botón de gamepad.
Buscador de información de videos
Emulation Station tiene un buscador integrado para localizar la información de juegos e imágenes, pero no para videos. Además, si las vistas previas del video son compatibles dependiendo de los temas elegidos, se reproducen a través de VLC, que no permite aceleración en el Soc del ODROID-C0/C1. La consecuencia es que 320×240@30 FPS en h.264 es el tamaño más grande al que se puede jugar. Escribí y usé un script personalizado disponible en GitHub en http://bit.ly/2fGFSkU, que analiza la carpeta game de Emulation Station y rastrea videos desde www.gamesdatabase.org.
Lecciones aprendidas
- No hay forma de controlar correctamente la batería en un ODROID-C0
- Con solo una GPU Mali 450, incluso aumentando la frecuencia del reloj (overclock), aún sigue siendo lento para muchos juegos de N64 y Dreamcast
- Hay algunos fallos que parecen estar relacionados con el driver gráfico, como que Emulation Station no se sale correctamente, y hurrican a veces no se inicia con la resolución correcta
- No es posible utilizar un driver joypad apropiado basado en interrupciones, ya que no hay suficientes IRQ disponibles en el SoC.
- Se hace necesario disponer de un gestor de ventanas, de lo contrario, la pantalla completa no está disponible para los juegos y Emulation Station
- Reicast parece emular ruido de GDRom, realmente lo encuentro algo molesto
Puedes ver el GamODROID-C0 en acción en https://youtu.be/3hxYhH7AFYU. Para comentarios, preguntas y sugerencias, visita el post original del blog en http://bit.ly/2khNDTz.
Be the first to comment