De ESP-GameBoy is een project dat de ESP32-S3 omvormt tot een headless Game Boy (DMG) emulator. In plaats van een eigen scherm, fungeert het bord als Wi-Fi access point dat video en audio via WebSockets streamt naar een browser op een telefoon of computer.
Belangrijkste kenmerken:
- Streaming: Video (160×144) en audio (8-bit mono PCM) worden verzonden naar een web-UI.
- Opslag: ROM's worden opgeslagen op het flashgeheugen (LittleFS) van de ESP32 en kunnen draadloos via de browser worden geüpload.
- Bediening: De besturing verloopt via on-screen knoppen in de browser of via een toetsenbord op een desktop.
- Hardware: Vereist een ESP32-S3 N16R8 board.
- Software: Installatie vindt plaats via PlatformIO, waarbij zowel de firmware als het bestandssysteem (voor de web-interface) geflasht moeten worden.
Het systeem ondersteunt automatische save-data voor cartridges met batterij-RAM en biedt diverse instellingen voor haptische feedback en streaming-buffers om de prestaties te optimaliseren.
ESP-GameBoy: Headless Game Boy-emulator voor ESP32-S3
ROM's worden opgeslagen op het flashgeheugen van de ESP32. Deze kunnen vanaf de telefoon worden geüpload, waardoor het niet nodig is om een cartridge in de firmware te integreren.
Let op: Gebruik uitsluitend legaal verkregen ROM's.
Technische Specificaties
Systeemarchitectuur
- ESP32 Core 1 (Peanut-GB) → frame → WebSocket binary → Phone browser (Canvas + Web Audio)
- Phone browser (touch/keyboard) → controller bitmask (1-byte) → ESP32
Netwerk en Streaming
- Wi-Fi: Open netwerk genaamd
ESP-GameBoy (kanaal 1, IP-adres gewoonlijk 192.168.4.1).
- Video: 160×144, packed 2-bit (5760 bytes per frame).
- Audio: 8-bit mono PCM.
- Flash-bibliotheek: Ongeveer 14 MB LittleFS voor
.gb-bestanden (maximaal 2 MB per bestand).
Benodigdheden
Hardware
- ESP32-S3 N16R8 (16 MB flash + 8 MB OPI PSRAM) — dit is het standaardbord.
- USB-C kabel die data kan overbrengen (geen 'charge-only' kabel).
- USB-stroombron: computer, telefoonlader of powerbank.
- Telefoon of computer met Wi-Fi en een browser (Chrome op Android werkt goed).
Software
- Cursor of VS Code.
- PlatformIO IDE-extensie (wordt aanbevolen door het project).
- Python (wordt automatisch geïnstalleerd via PlatformIO).
Installatie en Configuratie
1. Het project verkrijgen
Kloon de repository via Git:
git clone https://github.com/Artificial-Age/ESP32Gameboy.git
cd ESP32Gameboy
Alternatief kan het ZIP-bestand vanaf GitHub worden gedownload en uitgepakt. Open de map in Cursor of VS Code en installeer de PlatformIO IDE-extensie en de Espressif toolchain wanneer daarom wordt gevraagd.
2. Web UI op het bestandssysteem plaatsen
LittleFS wordt gebouwd vanuit de data/ map. Deze moet synchroon lopen met de frontend/ map:
| Bron (bewerk hier) | Kopieer naar (wordt geflasht) |
frontend/index.html | data/index.html |
frontend/style.css | data/style.css |
frontend/app.js | data/app.js |
Bij een clone van de repo zijn deze bestanden al aanwezig in data/. Kopieer ze opnieuw telkens wanneer de UI wordt gewijzigd. Plaats geen auteursrechtelijk beschermde .gb-bestanden in data/ als je van plan bent deze te commiten of te pushen; ROM-bestanden staan in de .gitignore.
3. Het bord aansluiten en de seriële poort bepalen
Verbind de ESP32-S3 via USB-C.
- Windows: Ga naar Apparaatbeheer → Poorten (COM & LPT) en noteer het COM-nummer (bijv.
COM14).
- macOS / Linux: De poort ziet eruit als
/dev/cu.usbmodem* of /dev/ttyACM0.
Mocht de poort niet verschijnen, probeer dan een andere kabel, een andere USB-poort, of houd de BOOT-knop ingedrukt tijdens het aansluiten. PlatformIO detecteert de poort meestal automatisch, maar indien de upload mislukt, kun je deze handmatig instellen in platformio.ini:
upload_port = COM14
monitor_port = COM14
De VS Code-taken in .vscode/tasks.json staan momenteel ingesteld op COM14. Pas dit aan naar jouw poort, of gebruik de PlatformIO-toolbarknoppen.
4. Firmware bouwen en uploaden
Dit schrijft de emulator naar het flashgeheugen, maar kopieert geen web UI of ROM's.
- PlatformIO toolbar: Klik op het vinkje (Build), daarna op de rechterpijl (Upload).
- Terminal:
pio run -e esp32-s3-n16r8 -t upload
Indien de seriële poort niet in downloadmodus gaat, houd dan BOOT ingedrukt, start de upload en laat BOOT dan los. De standaardomgeving is esp32-s3-n16r8 (alias: esp32-s3) met een partitietabel van 2 MB app + ~14 MB LittleFS (partitions/n16r8_romlib.csv).
5. LittleFS-image uploaden (Web UI)
Hiermee flash je de HTML-, CSS- en JS-bestanden uit de data/ map. Dit moet minimaal één keer gebeuren bij een nieuw bord, en telkens na een wijziging in de UI.
- PlatformIO toolbar: Klik op het cloud-upload icoon — “Upload Filesystem (LittleFS)”.
- Terminal:
pio run -e esp32-s3-n16r8 -t uploadfs
Optionele seriële log: pio device monitor -e esp32-s3-n16r8. Je zou het volgende moeten zien: [WiFi] AP SSID=ESP-GameBoy IP=192.168.4.1
6. Verbinding maken met de telefoon
Verbind de telefoon met het Wi-Fi netwerk ESP-GameBoy (open, geen wachtwoord). Let op: je verliest tijdens deze verbinding je normale internettoegang.
Het 'captive-portal' (aanmeldingsscherm) kan verschijnen. Dit is niet de Game Boy. Tik op de link naar het huidige adres van de ESP (meestal http://192.168.4.1/) of open dit handmatig in Chrome op Android. De echte pagina bevat het Game Boy-scherm, D-pad, A/B, Select en Start.
Belangrijk: Het aanmeldingsvenster kan geen besturingen, WebSocket-video of audio uitvoeren. Gebruik altijd een volledige browser. Er kan slechts één telefoon tegelijk verbinding maken.
7. Games uploaden (ROM-bibliotheek)
Games staan op de ESP32, niet op de telefoon.
- Tik op ⚙ Settings.
- Open ROM library. De flash-opslagmeter toont het verbruikte, vrije en totale geheugen.
- Tik op Add ROM to library en selecteer een
.gb-bestand (max. 2 MB per stuk).
- Wacht tot de voortgangsbalk klaar is. Je kunt meerdere games toevoegen tot het geheugen vol is.
- Tik op Play bij een titel. Het apparaat slaat de huidige cartridge indien nodig automatisch op en herstart in de gekozen ROM.
Mocht de telefoon de verbinding verliezen tijdens het herstarten, maak dan opnieuw verbinding met ESP-GameBoy en open de UI. Tik eenmaal op het scherm om de audio te ontgrendelen.
8. Spelen
De besturing is als volgt verdeeld:
| Actie | On-screen | Toetsenbord |
| D-Pad | pad | Pijltjestoetsen |
| A | A | Z of A |
| B | B | X of B |
| Select | SELECT | Shift of Q |
| Start | START | Enter of W |
Extra opties in Settings:
- Button haptics: Korte vibratie bij indrukken (ondersteunde Android-browsers).
- Stream buffer: Standaard 48 ms. Lager is sneller (snappier); hoger is vloeiender bij instabiel Wi-Fi.
- Reboot: Wis save-data en herstart de SoftAP.
Bij sommige telefoons kan de SoftAP-bandbreedte onder de 60 FPS zakken. De firmware gooit frames weg wanneer de WebSocket-wachtrij vol is, in plaats van de emulator te pauzeren.
Save-data
Cartridges met batterij-RAM worden automatisch opgeslagen in /saves/<name>.sav (ongeveer elke 15 seconden bij wijzigingen, en voor een herstart of ROM-wissel).
In Settings → Save data kun je:
.sav downloaden.
.sav uploaden (het apparaat herstart om dit toe te passen).
- Save verwijderen (wist flash + RAM, gevolgd door een herstart).
Probleemoplossing
| Symptoom | Mogelijke oplossing |
| Upload mislukt / poort bezet | Sluit Serial Monitor; trek de kabel eruit en stop hem er opnieuw in; houd BOOT ingedrukt. |
| Verkeerde COM-poort | Stel upload_port in platformio.ini in; pas .vscode/tasks.json aan indien van toepassing. |
| Wi-Fi is zichtbaar maar pagina is leeg | Je bevindt je nog in het captive-portal; open de link in Chrome. |
| Geen audio | Tik eenmaal op het scherm na het starten van 'Play'; controleer of de telefoon op stil/mute staat. |
| "Idle — upload a ROM" in seriële log | De firmware werkt, maar er is geen cartridge geselecteerd; gebruik Settings → ROM library. |
| UI ziet er oud uit na code-wijziging | Je hebt de firmware geüpload maar niet de LittleFS; voer uploadfs opnieuw uit. |
| Telefoon blijft niet verbonden | Blijf dicht bij het apparaat; er is slechts één client toegestaan; herstart het bord via Settings of USB. |
Projectstructuur
platformio.ini: Bordinstellingen, partities, libraries.
partitions/: 16 MB layout (waarvan ~14 MB voor de ROM-bibliotheek).
src/main.cpp: Wi-Fi AP, captive portal, Peanut-GB, WebSocket.
src/link_radio.cpp: Bewijs van ESP-NOW radio (nog geen functionele Pokémon-kabel).
src/minigb_apu.c: Game Boy APU.
include/: peanutgb.h, minigbapu.h, link_radio.h.
frontend/: Broncode van de Web UI.
data/: LittleFS-image (kopie van de UI-bestanden).
Kerntechnologieën:
- Emulator core: Peanut-GB (MIT).
- Web stack: ESPAsyncWebServer + AsyncTCP.
- Fase 2 (ESP-NOW link cable): Dit is momenteel enkel een radio-bewijs (via Settings → Link radio proof) en nog geen werkende Pokémon-kabel.
ESP-GameBoy: Headless Game Boy-emulator voor ESP32-S3
ROM's worden opgeslagen op het flashgeheugen van de ESP32. Deze kunnen vanaf de telefoon worden geüpload, waardoor het niet nodig is om een cartridge in de firmware te integreren.
Let op: Gebruik uitsluitend legaal verkregen ROM's.
Technische Specificaties
Systeemarchitectuur
- ESP32 Core 1 (Peanut-GB) → frame → WebSocket binary → Phone browser (Canvas + Web Audio)
- Phone browser (touch/keyboard) → controller bitmask (1-byte) → ESP32
Netwerk en Streaming
- Wi-Fi: Open netwerk genaamd
ESP-GameBoy (kanaal 1, IP-adres gewoonlijk 192.168.4.1).
- Video: 160×144, packed 2-bit (5760 bytes per frame).
- Audio: 8-bit mono PCM.
- Flash-bibliotheek: Ongeveer 14 MB LittleFS voor
.gb-bestanden (maximaal 2 MB per bestand).
Benodigdheden
Hardware
- ESP32-S3 N16R8 (16 MB flash + 8 MB OPI PSRAM) — dit is het standaardbord.
- USB-C kabel die data kan overbrengen (geen 'charge-only' kabel).
- USB-stroombron: computer, telefoonlader of powerbank.
- Telefoon of computer met Wi-Fi en een browser (Chrome op Android werkt goed).
Software
- Cursor of VS Code.
- PlatformIO IDE-extensie (wordt aanbevolen door het project).
- Python (wordt automatisch geïnstalleerd via PlatformIO).
Installatie en Configuratie
1. Het project verkrijgen
Kloon de repository via Git:
git clone https://github.com/Artificial-Age/ESP32Gameboy.git
cd ESP32Gameboy
Alternatief kan het ZIP-bestand vanaf GitHub worden gedownload en uitgepakt. Open de map in Cursor of VS Code en installeer de PlatformIO IDE-extensie en de Espressif toolchain wanneer daarom wordt gevraagd.
2. Web UI op het bestandssysteem plaatsen
LittleFS wordt gebouwd vanuit de data/ map. Deze moet synchroon lopen met de frontend/ map:
| Bron (bewerk hier) | Kopieer naar (wordt geflasht) |
frontend/index.html | data/index.html |
frontend/style.css | data/style.css |
frontend/app.js | data/app.js |
Bij een clone van de repo zijn deze bestanden al aanwezig in data/. Kopieer ze opnieuw telkens wanneer de UI wordt gewijzigd. Plaats geen auteursrechtelijk beschermde .gb-bestanden in data/ als je van plan bent deze te commiten of te pushen; ROM-bestanden staan in de .gitignore.
3. Het bord aansluiten en de seriële poort bepalen
Verbind de ESP32-S3 via USB-C.
- Windows: Ga naar Apparaatbeheer → Poorten (COM & LPT) en noteer het COM-nummer (bijv.
COM14).
- macOS / Linux: De poort ziet eruit als
/dev/cu.usbmodem* of /dev/ttyACM0.
Mocht de poort niet verschijnen, probeer dan een andere kabel, een andere USB-poort, of houd de BOOT-knop ingedrukt tijdens het aansluiten. PlatformIO detecteert de poort meestal automatisch, maar indien de upload mislukt, kun je deze handmatig instellen in platformio.ini:
upload_port = COM14
monitor_port = COM14
De VS Code-taken in .vscode/tasks.json staan momenteel ingesteld op COM14. Pas dit aan naar jouw poort, of gebruik de PlatformIO-toolbarknoppen.
4. Firmware bouwen en uploaden
Dit schrijft de emulator naar het flashgeheugen, maar kopieert geen web UI of ROM's.
- PlatformIO toolbar: Klik op het vinkje (Build), daarna op de rechterpijl (Upload).
- Terminal:
pio run -e esp32-s3-n16r8 -t upload
Indien de seriële poort niet in downloadmodus gaat, houd dan BOOT ingedrukt, start de upload en laat BOOT dan los. De standaardomgeving is esp32-s3-n16r8 (alias: esp32-s3) met een partitietabel van 2 MB app + ~14 MB LittleFS (partitions/n16r8_romlib.csv).
5. LittleFS-image uploaden (Web UI)
Hiermee flash je de HTML-, CSS- en JS-bestanden uit de data/ map. Dit moet minimaal één keer gebeuren bij een nieuw bord, en telkens na een wijziging in de UI.
- PlatformIO toolbar: Klik op het cloud-upload icoon — “Upload Filesystem (LittleFS)”.
- Terminal:
pio run -e esp32-s3-n16r8 -t uploadfs
Optionele seriële log: pio device monitor -e esp32-s3-n16r8. Je zou het volgende moeten zien: [WiFi] AP SSID=ESP-GameBoy IP=192.168.4.1
6. Verbinding maken met de telefoon
Verbind de telefoon met het Wi-Fi netwerk ESP-GameBoy (open, geen wachtwoord). Let op: je verliest tijdens deze verbinding je normale internettoegang.
Het 'captive-portal' (aanmeldingsscherm) kan verschijnen. Dit is niet de Game Boy. Tik op de link naar het huidige adres van de ESP (meestal http://192.168.4.1/) of open dit handmatig in Chrome op Android. De echte pagina bevat het Game Boy-scherm, D-pad, A/B, Select en Start.
Belangrijk: Het aanmeldingsvenster kan geen besturingen, WebSocket-video of audio uitvoeren. Gebruik altijd een volledige browser. Er kan slechts één telefoon tegelijk verbinding maken.
7. Games uploaden (ROM-bibliotheek)
Games staan op de ESP32, niet op de telefoon.
- Tik op ⚙ Settings.
- Open ROM library. De flash-opslagmeter toont het verbruikte, vrije en totale geheugen.
- Tik op Add ROM to library en selecteer een
.gb-bestand (max. 2 MB per stuk).
- Wacht tot de voortgangsbalk klaar is. Je kunt meerdere games toevoegen tot het geheugen vol is.
- Tik op Play bij een titel. Het apparaat slaat de huidige cartridge indien nodig automatisch op en herstart in de gekozen ROM.
Mocht de telefoon de verbinding verliezen tijdens het herstarten, maak dan opnieuw verbinding met ESP-GameBoy en open de UI. Tik eenmaal op het scherm om de audio te ontgrendelen.
8. Spelen
De besturing is als volgt verdeeld:
| Actie | On-screen | Toetsenbord |
| D-Pad | pad | Pijltjestoetsen |
| A | A | Z of A |
| B | B | X of B |
| Select | SELECT | Shift of Q |
| Start | START | Enter of W |
Extra opties in Settings:
- Button haptics: Korte vibratie bij indrukken (ondersteunde Android-browsers).
- Stream buffer: Standaard 48 ms. Lager is sneller (snappier); hoger is vloeiender bij instabiel Wi-Fi.
- Reboot: Wis save-data en herstart de SoftAP.
Bij sommige telefoons kan de SoftAP-bandbreedte onder de 60 FPS zakken. De firmware gooit frames weg wanneer de WebSocket-wachtrij vol is, in plaats van de emulator te pauzeren.
Save-data
Cartridges met batterij-RAM worden automatisch opgeslagen in /saves/<name>.sav (ongeveer elke 15 seconden bij wijzigingen, en voor een herstart of ROM-wissel).
In Settings → Save data kun je:
.sav downloaden.
.sav uploaden (het apparaat herstart om dit toe te passen).
- Save verwijderen (wist flash + RAM, gevolgd door een herstart).
Probleemoplossing
| Symptoom | Mogelijke oplossing |
| Upload mislukt / poort bezet | Sluit Serial Monitor; trek de kabel eruit en stop hem er opnieuw in; houd BOOT ingedrukt. |
| Verkeerde COM-poort | Stel upload_port in platformio.ini in; pas .vscode/tasks.json aan indien van toepassing. |
| Wi-Fi is zichtbaar maar pagina is leeg | Je bevindt je nog in het captive-portal; open de link in Chrome. |
| Geen audio | Tik eenmaal op het scherm na het starten van 'Play'; controleer of de telefoon op stil/mute staat. |
| "Idle — upload a ROM" in seriële log | De firmware werkt, maar er is geen cartridge geselecteerd; gebruik Settings → ROM library. |
| UI ziet er oud uit na code-wijziging | Je hebt de firmware geüpload maar niet de LittleFS; voer uploadfs opnieuw uit. |
| Telefoon blijft niet verbonden | Blijf dicht bij het apparaat; er is slechts één client toegestaan; herstart het bord via Settings of USB. |
Projectstructuur
platformio.ini: Bordinstellingen, partities, libraries.
partitions/: 16 MB layout (waarvan ~14 MB voor de ROM-bibliotheek).
src/main.cpp: Wi-Fi AP, captive portal, Peanut-GB, WebSocket.
src/link_radio.cpp: Bewijs van ESP-NOW radio (nog geen functionele Pokémon-kabel).
src/minigb_apu.c: Game Boy APU.
include/: peanutgb.h, minigbapu.h, link_radio.h.
frontend/: Broncode van de Web UI.
data/: LittleFS-image (kopie van de UI-bestanden).
Kerntechnologieën:
- Emulator core: Peanut-GB (MIT).
- Web stack: ESPAsyncWebServer + AsyncTCP.
- Fase 2 (ESP-NOW link cable): Dit is momenteel enkel een radio-bewijs (via Settings → Link radio proof) en nog geen werkende Pokémon-kabel.