Multi-System Retro Emulator for ESP32-FabGL
License: GPL v3 Platform: ESP32 Display: VGA
- Description
- Supported Systems
- Features
- Hardware Requirements
- Pin Configuration
- Installation
- SD Card Structure
- Usage
- Building from Source
- Development
- Troubleshooting
- Known Limitations
- Acknowledgements
- License
Retro-Gamer is a multi-system retro emulator firmware for ESP32-based devices with VGA output via FabGL. It brings retro gaming to life on a big screen with crisp 320x240 resolution and 64 colors (RGB222).
This project is a port and enhancement of ducalex's Retro-Go, adapted to run on the FabGL VGA framework. It features a unified launcher for all supported systems, in-game menus, save states, and extensive customization options.
Unlike the original Retro-Go (which was designed for handheld devices with small LCD screens), Retro-Gamer is optimized for VGA displays and PS/2 keyboard input, making it perfect for DIY retro gaming consoles and arcade cabinets.
| System | Core | Extensions | Status |
|---|---|---|---|
| NES | nofrendo | .nes | ✅ Stable |
| Game Boy | gnuboy | .gb | ✅ Stable |
| Game Boy Color | gnuboy | .gbc | ✅ Stable |
| Sega Master System | smsplus | .sms | ✅ Stable |
| Sega Game Gear | smsplus | .gg | ✅ Stable |
| SG-1000 | smsplus | .sg | ✅ Stable |
| ColecoVision | smsplus | .col | ✅ Stable |
| PC Engine / TurboGrafx | pce-go | .pce | ✅ Stable |
| SNES / Super Famicom | snes9x | .sfc .smc | |
| Atari Lynx | handy | .lnx | ✅ Stable |
| Mega Drive / Genesis | gwenesis | .md .gen .bin .smd |
| Feature | Description |
|---|---|
| 11 Emulators | NES, GB/GBC, SMS, GG, SG-1000, ColecoVision, PCE, SNES, Lynx, Genesis |
| In-Game Menu | Save/Load states (4 slots), turbo, palette, rotate, sound toggle, reset, quit |
| Favorites & Recent | Quick access to your favorite and recently played games |
| Save States | 4 slots per game |
| WiFi File Manager | Browser-based file upload/download |
| VGA Output | 320x240 resolution with 64 colors (RGB222) |
| PS/2 Keyboard | Full keyboard input with WASD support |
| ROM Cache | Fast boot times with cached ROM list |
| Sound Control | Toggle audio ON/OFF |
| Turbo / Fast Forward | 2× speed with continuous audio |
- ESP32 with PSRAM (mandatory)
- VGA compatible display (standard VGA monitor)
- PS/2 Keyboard
- MicroSD Card (for ROMs and saves)
- LilyGO TTGO VGA32
- Olimex ESP32-SBC-FabGL Rev B
| Function | GPIO Pin |
|---|---|
| VGA Red 0 | GPIO 22 |
| VGA Red 1 | GPIO 21 |
| VGA Green 0 | GPIO 19 |
| VGA Green 1 | GPIO 18 |
| VGA Blue 0 | GPIO 5 |
| VGA Blue 1 | GPIO 4 |
| VGA HSYNC | GPIO 23 |
| VGA VSYNC | GPIO 15 |
| SD CS | GPIO 13 |
| Keyboard Clock | GPIO 33 |
| Keyboard Data | GPIO 32 |
| Audio DAC | GPIO 25 |
Same as above, except SD CS = GPIO 4
Create the following folder structure on your SD card:
SD Card
├── retro-go/
│ ├── config/
│ │ ├── favorites.txt
│ │ ├── recent.txt
│ │ └── wifi.json (optional)
│ └── saves/
│ ├── nes/
│ ├── gb/
│ ├── sms/
│ ├── gg/
│ ├── pce/
│ ├── snes/
│ ├── lnx/
│ ├── md/
│ └── misc/
└── roms/
├── nes/ (NES .nes, .fc)
├── gb/ (Game Boy .gb)
├── gbc/ (Game Boy Color .gbc)
├── sms/ (Master System .sms)
├── gg/ (Game Gear .gg)
├── sg1000/ (SG-1000 .sg)
├── pce/ (PC Engine .pce)
├── snes/ (SNES .sfc, .smc)
├── lnx/ (Lynx .lnx)
├── col/ (ColecoVision .col)
└── md/ (Mega Drive/Genesis .md, .gen, .bin, .smd)
- Download the latest firmware from the Releases page.
- Connect your ESP32 board to your computer via USB.
- Flash using esptool:
esptool.py write_flash --flash_size detect 0x0 RetroGamer.binOr use the esptool web version for a GUI-based flashing experience.
Place your ROM files in the corresponding folders on the SD card (see SD Card Structure above).
| System | Folder | Extensions |
|---|---|---|
| NES | /roms/nes/ | .nes |
| Game Boy | /roms/gb/ | .gb |
| Game Boy Color | /roms/gbc/ | .gbc |
| Master System | /roms/sms/ | .sms |
| Game Gear | /roms/gg/ | .gg |
| SG-1000 | /roms/sg1000/ | .sg |
| PC Engine | /roms/pce/ | .pce |
| SNES | /roms/snes/ | .sfc, .smc |
| Lynx | /roms/lnx/ | .lnx |
| ColecoVision | /roms/col/ | .col |
| Mega Drive / Genesis | /roms/md/ | .md, .gen, .bin, .smd |
Save states are stored in:
/retro-go/saves/<system>/<rom_name>.sav<slot>Example: /retro-go/saves/nes/Super_Mario_Bros.sav0
| Key | Action |
|---|---|
| ↑ / ↓ / W / S | Navigate ROM list |
| Enter | Play selected ROM |
| F | Toggle favorite |
| Tab | Switch view (All / Favorites / Recent) |
| ESC | Refresh ROM list and update cache |
| Key | Action |
|---|---|
| ↑ / ↓ / ← / → (or WASD) | D-Pad |
| Z / Space | A Button |
| X / Ctrl | B Button |
| Enter | Start |
| Right Shift | Select |
| Tab | Toggle Turbo Mode |
| ESC | Open In-Game Menu |
Press ESC during gameplay to open the in-game menu, which provides:
- Resume: Return to game
- Save State [0-3]: Save current state to selected slot
- Load State [0-3]: Load state from selected slot
- Turbo: Toggle fast-forward mode
- Sound: Toggle audio ON/OFF
- Palette: Change color palette (NES/GB only)
- Rotate: Rotate screen (Lynx only)
- Reset Game: Reset the current game
- Quit to Menu: Exit to launcher
- Create
/retro-go/config/wifi.jsonon your SD card:
{
"ssid0": "your-wifi-ssid",
"password0": "your-wifi-password"
}Up to 4 networks can be configured (ssid0-ssid3).
- Connect your ESP32 to the network (WiFi connection happens automatically on boot).
- Find the IP address in the boot screen (top-right corner).
- Open your web browser and navigate to
http://<IP_ADDRESS>/to manage files.
Press Tab in-game to toggle turbo mode. When enabled:
- The game runs at approximately 2× speed
- Audio is continuous (no interruptions)
- Useful for skipping long cutscenes or grinding in RPGs
Retro-Gamer uses a ROM cache to speed up boot times. The cache is stored at /retro-go/rom_cache.txt on your SD card.
When to refresh the cache:
- After adding new ROMs
- After removing ROMs
- If ROMs are not appearing correctly in the launcher
How to refresh the cache:
- From the launcher: Press ESC to force a cache refresh and rescan all ROM directories.
- Manual method: Delete the file
/retro-go/rom_cache.txtfrom your SD card and restart the device. The cache will be rebuilt automatically. - From the web interface: Use the WiFi file manager to navigate to
/retro-go/and deleterom_cache.txt, then restart the device.
The cache is automatically updated when:
- The system detects changes in ROM directories (based on file modification timestamps)
- You press ESC in the launcher
- Clone the repository:
git clone https://github.com/foky26/Retro-Gamer.git
cd Retro-Gamer- Set up the ESP-IDF environment:
. $HOME/esp/esp-idf/export.sh- Build the firmware:
idf.py build- Flash to your device:
idf.py flash| Metric | Value |
|---|---|
| Flash Usage | ~1.9 MB / 3.14 MB (61%) |
| DRAM Usage | ~120 KB / 327 KB (36%) |
| Free DRAM | ~207 KB |
| PSRAM | ~4 MB (for ROM data, framebuffers, audio) |
The project includes a comprehensive debug system controlled by DEBUG_ENABLED:
// In config.h or debug.h
#define DEBUG_ENABLED 1 // Enable debug output
#define DEBUG_ENABLED 0 // Disable debug outputDebug macros available:
DBG_ERROR(tag, format, ...)- Critical errors (red)DBG_WARN(tag, format, ...)- Warnings (yellow)DBG_INFO(tag, format, ...)- Information (white)DBG_VERBOSE(tag, format, ...)- Detailed debug (gray)
Retro_Gamer.ino ← Main: hardware init, launcher UI, game loop ├── src/ │ ├── debug.h ← Debug system (Serial) │ ├── nes_bridge.c/h ← NES emulator bridge │ ├── gb_bridge.c/h ← Game Boy bridge │ ├── sms_bridge.c/h ← SMS/GG/SG-1000/ColecoVision bridge │ ├── pce_bridge.c/h ← PC Engine bridge │ ├── snes_bridge.c/h ← SNES bridge │ ├── lynx_bridge.c/h ← Atari Lynx bridge │ ├── genesis_bridge.c/h ← Mega Drive bridge │ ├── wifi_manager.* ← WiFi + HTTP server │ └── sound_control.c/h ← Audio control
- Create a new bridge file in
src/<system>_bridge.c - Implement the required bridge functions:
bool <system>_bridge_init(int sample_rate)int <system>_bridge_load_rom(const char *path)void <system>_bridge_run_frame(bool draw)void <system>_bridge_set_input(uint32_t buttons)void <system>_bridge_shutdown(void)uint8_t* <system>_bridge_get_framebuffer(int *width, int *height)int16_t* <system>_bridge_get_audio(int *num_samples)
- Add the system to
emu_type_tinRetro_Gamer.ino - Update
getEmuType(),emuName(), andemuShortName()
| Problem | Solution |
|---|---|
| Black/no VGA output | Check VGA cable connection. Ensure monitor supports 640×480@60Hz. |
| "PSRAM not found" | Your board must have ESP32-WROVER module (with PSRAM). Regular ESP32 not supported. |
| SD card not detected | Format as FAT32 (not exFAT). Check card is ≤32GB. |
| Keyboard not working | Must be PS/2 protocol (not USB-to-PS/2 adapter). Check CLK=33, DAT=32. |
| No audio | Audio output is on GPIO 25 (internal DAC). Connect amplified speaker. |
| ROM list empty | ROMs must be in /roms/{platform}/ directories. Check file extensions. |
| SNES very slow | Expected — ESP32 at 240MHz struggles with SNES emulation. |
| WiFi won't work | Check wifi.json format. Ensure SD card is properly inserted. |
| Compile error: DRAM overflow | Set DEBUG_ENABLED 0 to reduce memory usage. |
- Save States: Work for most systems but may have occasional issues with some games
- SNES Performance: ~15-25 FPS due to ESP32 CPU limitations
- VGA Color Depth: 64 colors (R2G2B2) — adequate for retro systems
- Audio: 8-bit DAC output at 22050Hz — acceptable for retro audio
- No Bluetooth: Bluetooth gamepad support is not implemented
- Single Player Only: No multiplayer/netplay support
- The NES/GB/SMS emulators and base library were originally from the "Triforce" fork of the official Go-Play firmware by crashoverride, Nemo1984, and many others.
- The design of the launcher was originally inspired/copied from pelle7's go-emu.
- PCE-GO is a fork of HuExpress and pelle7's port was used as reference.
- The Lynx emulator is a port of libretro-handy.
- The SNES emulator is a port of Snes9x 2005.
- The Genesis emulator is a port of Gwenesis by bzhxx.
- PNG support is provided by lodepng.
- Special thanks to the ODROID-GO community for encouraging the development of retro-go!
- ducalex for creating and maintaining the original Retro-Go firmware
- UfkuAcik for the initial port to FabGL VGA framework
- FabGL library by Francesco Di Vittorio for providing the VGA, PS/2, and audio framework
- The FabGL community for their support and contributions
- All the emulator authors whose work made this project possible
- The open-source community for their continuous support and contributions
This project is licensed under the GNU General Public License v3.0 - see the COPYING file for details.
- handy-go/components/handy (Lynx emulator, zlib license)
Retro-Gamer - Bringing retro gaming to VGA displays, one pixel at a time! 🎮