GameBoy on E-Paper ESP32 at 30FPS [video]

Hacker News Top Tools

Summary

The author wrote a custom display driver for an ESP32 e-paper development board with a dedicated display controller. By shortening waveforms, budgeting drive time per pixel, and calibrating grayscale, they boosted the Game Boy emulator from under 2 FPS to around 30 FPS and achieved true four-level grayscale output without relying on dithering.

No content available
Original Article
View Cached Full Text

Cached at: 10/11/26, 06:38 AM

# Running a Game Boy Emulator on an ESP32 + E-Paper Display: A Driver Overhaul from 2 FPS to 30 FPS TL;DR: The author wrote a custom driver for an ESP32 e-paper development board with a dedicated display controller. By shortening waveforms, using per-pixel drive budgets, and calibrating grayscale transitions, he boosted a Game Boy emulator from under 2 frames per second to around 30 frames per second and achieved true four-level grayscale output without dithering. ## The Final Result This is an ESP32 development board with a small e-paper display, running a Game Boy emulator at roughly 30 frames per second using the author's custom display driver. With the board's stock driver, it should theoretically manage around 3 frames per second, but in practice it does not even reach 2. So how did he turn a slideshow-like experience into what it is now? ## Why E-Paper Is Slow Unlike conventional displays such as LCDs or OLEDs, e-paper physically stores images using charged black and white pigment particles. By changing the electric field, the screen pushes the pigment particles toward or away from the surface, ultimately producing black or white pixels. This typically requires a sequence of electrical pulses called a "waveform" to move the pigment back and forth before finally driving it into the state required for the new image. This produces a clean image without leaving too much of the previous frame behind. But the process is very time-consuming. The WaveShare datasheet specifies roughly 300 milliseconds for a partial refresh. That is nowhere near fast enough for games. ## Why Play Game Boy on E-Paper? At the time, the author was building a personal device around this development board, envisioning something with Anki flashcards, voice memos, and perhaps the ability to serve as a small e-reader. But the UI—such as navigating menus—was painfully slow. Initially, he thought that was simply how e-paper worked: it was slow. But he knew fast e-paper was possible because he had previously seen a video: Zeph Ray had already created Paperboy, a Game Boy emulator running on e-paper. However, Paperboy used completely different display hardware. Its panel directly exposed the raw Roland Column interface, whereas the author's board had a dedicated display controller that actually drove the panel. He could not bypass that controller, which meant he could not simply port Paperboy's display driver. He had to build his own driver for this controller. ## Step One: Shortening the Waveform First, he needed to see how fast this display controller could run. The first thing the author tried was shortening the waveform. A standard waveform spends hundreds of milliseconds driving the pigment to produce a clean image, so he gradually shortened the sequence, testing how much he could remove before the image started looking wrong. Surprisingly, he could remove quite a lot. He ultimately reduced the waveform to just two drive steps, down from roughly 17. Including the processing time before and after, a complete update took around 50 milliseconds, approaching 20 updates per second. There was just one problem: the image looked terrible. ### Two Side Effects **Ghosting**: Parts of the image that should have disappeared remained clearly visible. Reducing the number of pulses in the waveform shortened the time each pixel had to transition to its target gray level. **The entire screen turning gray**: After running for a while, the whole screen gradually became grayer and grayer. ## Step Two: Per-Pixel Drive Budgets At this point, the author returned to Paperboy's approach: instead of driving the entire panel on every update, he maintained a state for each pixel and drove only the pixels that actually needed it. When a pixel changes, it receives a **drive budget**—a numerical value. Each time the driver sends a pulse to that pixel, its remaining budget decreases; once it has received enough driving, the driver stops driving it. This made stationary areas much cleaner and significantly reduced ghosting. The author found that a budget of roughly **6 to 8 drive pulses** was enough to complete a full transition from solid black to white. There was still a tradeoff: more drive pulses produced a clearer final pixel, but moving objects took longer to transition and looked blurrier. At this stage, 30 frames per second started to become feasible. The author then began cutting down the surrounding processing. After several rounds of lengthy, repeated debugging, scans now start roughly every **33 milliseconds**. In actual gameplay, the results were surprisingly good. ## Step Three: True Four-Level Grayscale The Game Boy has four gray levels, which had previously been simulated using black and white pixels through dithering. Paperboy did something similar, but its panel had a much higher resolution. The Game Boy's image is only **160x144 pixels**, so Paperboy could use multiple physical screen pixels to represent one Game Boy pixel. The author's screen, however, was only **200x200**, leaving just one display pixel for each Game Boy pixel. So although dithering worked, its patterns were clearly visible, and the result was far inferior to true grayscale. ### Grayscale Discovered by Accident While wrestling with ghosting, the author noticed something interesting: the screen was already producing gray, just accidentally—the pigment does not instantly jump from black to white. That gave him an idea: could he deliberately stop driving halfway through a transition to produce these gray levels on demand? It turned out he could. ### The Challenge: Stable Grayscale During Changes Producing a static grayscale image is relatively easy, but maintaining stable gray levels while the image constantly changes is a completely different problem—**there are 12 possible transitions between four gray levels**, and they are not equivalent: transitioning from black to white requires different driving and a different budget than transitioning from white to light gray. So the author created tests for every transition. The basic test was simple: - Move a block of one gray level across a background of another gray level. - Does the block actually reach the desired gray level? - When it moves away, does the background return to its original gray level? Because the display controller cannot actually see the pigment particles, the author had to calibrate the model against the physical screen. He built a small setup that ran transition tests on the development board while taking photos and videos; he reviewed the results, adjusted parameters, and then reran the tests over and over. After a lot—and he says a lot—of calibration, the results started looking pretty good. They were still imperfect, but he had achieved true four-level grayscale Game Boy output without dithering. ## Audio: One Part That Was Easier Than Paperboy One part of this project was much simpler than Paperboy. Unlike the Paper S3, which only has a buzzer for sound, this board has a **dedicated audio codec and speaker**, meaning it can play the Game Boy emulator's audio directly, with quite good sound quality. ## Controllers and Future Plans By this point, the author was quite pleased with the results. The games were playable, and he enjoyed some great titles he had never had the chance to play before. He also modified a NAS controller design so it could connect over USB and communicate with the board, though any other Bluetooth controller should also be supported. The display driver is not finished yet: visually demanding scenes still occasionally drop below 30 fps, and there are some grayscale transitions he wants to calibrate further. Once he is satisfied, he will release the driver and the rest of the project on GitHub, along with the controller design files. The author specifically noted that without Zeph Ray's Paperboy, he would never have started this project. Zeph Ray's work inspired the project and provided the foundation for the per-pixel driving approach. ## A Spin-Off Project Remember the other project on this board that started all of this? Its UI and menus are now very fast too. The author is building something like a small operating system for this board, featuring: - A fully online Anki scheduler - Voice memos integrated with Obsidian - Possibly local speech-to-text functionality Source: GameBoy on E-Paper ESP32 at 30FPS — pizzaiolo (https://www.youtube.com/watch?v=XiZmM6hwwAU)

Similar Articles

GameBoy Emulator on ESP32 + Eink

Lobsters Hottest

The author successfully implemented a playable Gameboy emulator on the M5 Paper S3 (ESP32 S3 + e-ink display). By using high refresh rate driving, an optimized emulation core, and an innovative pseudo-polyphonic sound scheme, classic games run smoothly on the e-ink screen.

60fps Video on a CGA? – The GlyphBlaster

Hacker News Top

The GlyphBlaster is a Raspberry Pi Pico based device that replaces the font ROM on a CGA card, enabling 60fps video playback in text mode by using the font ROM readout as a pixel-addressable framebuffer.

Driving the GDEH0154D67 e-paper display with Rust

Lobsters Hottest

A developer documents rewriting the firmware for their SQFMI Watchy e-paper watch in Rust, detailing the challenges of Rust on ESP32 and the experience of writing an async e-paper display driver for the GDEH0154D67.