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

Hacker News Top 工具

摘要

作者为带专用显示控制器的 ESP32 墨水屏开发板自写显示驱动,通过缩短波形、逐像素驱动预算和灰度校准,把 Game Boy 模拟器从不到 2FPS 提升到约 30FPS,并实现了不依赖抖动的真正四灰度级输出。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/10/11 06:38

# 用 ESP32 + 墨水屏跑 Game Boy 模拟器:从 2FPS 到 30FPS 的驱动改造 TL;DR:作者为带专用显示控制器的 ESP32 墨水屏开发板自写驱动,通过缩短波形、逐像素驱动预算和灰度校准,把 Game Boy 模拟器从不到 2 帧每秒提升到约 30 帧每秒,并实现了不依赖抖动的真正四灰度级输出。 ## 最终效果 这是一块搭载小型墨水屏的 ESP32 开发板,通过作者自写的显示驱动,以大约 30 帧每秒的速度运行 Game Boy 模拟器。而使用开发板自带驱动的效果,理论上应该大约有 3 帧每秒,但实际表现连 2 帧都不到。 那么,是如何把它从幻灯片级别的体验变成现在这样的呢? ## 墨水屏为什么慢 与 LCD 或 OLED 等传统显示器不同,墨水屏通过带电的黑白颜料粒子来物理存储图像。通过改变电场,屏幕推动颜料粒子朝向或远离表面,最终呈现出黑色或白色的像素。 通常需要一系列称为"波形"的电脉冲,让颜料先来回运动,最后再将其驱动到新图像所需的状态。这样可以产生干净的画面,不会残留太多上一帧的图像。但这个过程非常耗时。 WaveShare 规格书上标明局部刷新大约需要 300 毫秒。这对游戏来说远远不够快。 ## 为什么在墨水屏上玩 Game Boy 作者当时正在基于这块开发板做一个个人设备,打算做一个有 Anki 卡片、语音备忘录,也许还能当小型电子阅读器的东西。但 UI——比如翻菜单——慢得令人痛苦。起初他觉得这就是墨水屏,它就是慢。 但他知道快速的墨水屏是可能的,因为他之前看过一个视频:Zeph Ray 已经做过 Paperboy——一个运行在墨水屏上的 Game Boy 模拟器。 不过 Paperboy 使用的显示硬件完全不同。它的面板直接暴露了原始的 Roland Column 接口,而作者的板子有一个专用的显示控制器,由它实际驱动面板。他无法绕过那个控制器,这意味着不能简单地移植 Paperboy 的显示驱动,必须为这个控制器自建一个驱动。 ## 第一步:缩短波形 首先需要看看这块显示控制器最快能跑多快。 作者尝试的第一件事是缩短波形。标准波形会花费数百毫秒来驱动颜料以产生干净的图像,于是他逐步缩短这个序列,测试能去掉多少而不让图像看起来不对。 出乎意料的是,能去掉的相当多。最终他把波形缩减到了只有两个驱动步骤,从大约 17 步降下来。加上前后的处理时间,一次完整更新大约需要 50 毫秒,接近每秒 20 次更新。 只有一个问题:图像看起来非常糟糕。 ### 两个副作用 **残影**:那些本该消失的图像部分仍然清晰可见。通过减少波形产生的脉冲数量,每个像素过渡到目标灰度所需的时间被缩短了。 **整屏变灰**:运行较长时间后,整个屏幕会逐渐变得越来越灰。 ## 第二步:逐像素驱动预算 这时作者回到了 Paperboy 的思路:不再每次更新都驱动整个面板,而是为每个像素维护状态,只驱动真正需要驱动的像素。 当一个像素发生变化时,它会获得一个**驱动预算**——一个数值。每次驱动器向该像素发送一个脉冲,剩余预算就减少;当它已经收到足够的驱动时,就停止驱动。 这让静止区域变得干净多了,并显著减少了残影。作者发现大约 **6 到 8 次驱动的预算**就足以完成一次从全黑到白的完整过渡。 仍然存在一个权衡:驱动次数越多,最终像素越清晰,但运动物体的过渡时间更长,看起来更模糊。 到了这个阶段,30 帧每秒开始变得可行。于是作者开始削减周围的处理经过几轮长时间的反复调试,扫描现在大约每 **33 毫秒**开始一次。在实际游戏体验中,效果出乎意料地好。 ## 第三步:真正的四灰度级 Game Boy 有四个灰度级,此前一直使用抖动(dithering)来用黑白像素模拟它们。Paperboy 也做了类似的事情,但它的面板分辨率高得多。 Game Boy 的图像只有 **160x144 像素**,所以 Paperboy 可以用多个物理屏幕像素来表示一个 Game Boy 像素。而作者的屏幕只有 **200x200**,每个 Game Boy 像素只能分到一个显示像素。所以虽然抖动确实有效,但那些图案清晰可见,效果远不如真正的灰度。 ### 意外发现的灰度 在与残影问题搏斗时,作者注意到了一个有趣的现象:屏幕已经在产生灰色了,只是纯属意外——颜料不会瞬间从黑跳到白。 于是他想到:如果在过渡中途故意停止驱动,能否按需产生这些灰度级呢?结果证明可以。 ### 难点:变化中的稳定灰度 产生静态灰度图像相对容易,但在图像不断变化的同时保持稳定的灰度是一个完全不同的问题——**四个灰度级之间有 12 种可能的过渡**,而且它们并不等价:从黑到白需要不同的驱动方式,与从白到浅灰不同,预算也不同。 所以作者为每一种过渡都建立了测试。基本测试很简单: - 将一个灰度的色块在另一个灰度的背景上移动 - 色块是否真的达到了想要的灰度? - 当它移走时,背景是否恢复到了它开始时的灰度? 由于显示控制器实际上看不到颜料粒子,作者必须针对实际屏幕来校准模型。他搭建了一个小型装置,在开发板上运行过渡测试,同时拍摄照片和视频;审查结果,调整参数,然后一遍又一遍地重新运行测试。 经过大量——他说是大量的——校准后,效果开始看起来还不错。它仍然不完美,但让他得到了不依赖抖动的真正四灰度级 Game Boy 输出。 ## 音频:比 Paperboy 更简单的一部分 这个项目有一部分比 Paperboy 简单得多。不同于只有蜂鸣器发声的 Paper S3,这块板子有一个**专用的音频编解码器和扬声器**,这意味着可以直接播放 Game Boy 模拟器的音频,而且音质也相当不错。 ## 控制器与后续计划 到这时,作者对结果已经相当满意。游戏可以玩了,他也享受了一些过去没有机会玩到的佳作。 他还改装了一款 NAS 控制器设计,让它可以通过 USB 插入并与板子通信,但同时也应该支持其他任何蓝牙控制器。 显示驱动还没有完成:画面负载重的场景偶尔还是会掉到 30fps 以下,还有一些灰度过渡想进一步校准。等他满意之后,会把驱动和项目的其他部分一起发布到 GitHub 上,连同控制器的设计文件。 作者特别提到:如果没有 Zeph Ray 的 Paperboy,他绝对不会开始这个项目。他的工作是这个项目的灵感来源,也是逐像素驱动方法的基础。 ## 衍生项目 还记得那个引发这一切的板子上的另一个项目吗?它的 UI 和菜单现在也变得非常快了。 作者正在为这块板子打造一个类似小型操作系统的东西,带有: - 完全在线的 Anki 计划器 - 与 Obsidian 集成的语音备忘录 - 可能的本地语音转文字功能 Source: [GameBoy on E-Paper ESP32 at 30FPS — pizzaiolo](https://www.youtube.com/watch?v=XiZmM6hwwAU)

相似文章

GameBoy Emulator on ESP32 + Eink

Lobsters Hottest

作者成功在M5 Paper S3(ESP32 S3+电子墨水屏)上实现可玩的Gameboy模拟器,通过高刷新率驱动、优化模拟核心和创新的伪复音声音方案,使经典游戏在电子墨水屏上流畅运行。

CGA上的60fps视频?– GlyphBlaster

Hacker News Top

GlyphBlaster是一款基于Raspberry Pi Pico的设备,它替换了CGA显卡上的字模ROM,通过将字模ROM读取作为像素可寻址帧缓冲区,在文本模式下实现了60fps的视频播放。

用 Rust 驱动 GDEH0154D67 电子纸显示屏

Lobsters Hottest

一位开发者记录了用 Rust 重写其 SQFMI Watchy 电子纸手表固件的过程,详细介绍了在 ESP32 上使用 Rust 所面临的挑战,以及为 GDEH0154D67 编写异步电子纸显示屏驱动的体验。