1. 从行车记录仪到复古游戏机的奇思妙想

几年前,我在整理一堆旧电子设备时,发现了一个被淘汰的旧款行车记录仪。它静静地躺在抽屉角落,屏幕已经有些划痕,但外壳依然坚固。当时我就在想,这玩意儿本质上不就是一块集成了摄像头、处理器、存储和屏幕的嵌入式系统吗?它能不能干点别的?这个念头,最终催生了一个非常有趣的项目:把一台报废的行车记录仪,改造成一台可以随时随地玩经典游戏的复古游戏机。

这个想法听起来有点天马行空,但背后的逻辑其实非常扎实。一台典型的行车记录仪,其硬件配置与早期的掌上游戏机或开源掌机有着惊人的相似性:它们通常都基于ARM架构的SoC(系统级芯片),运行着某个裁剪过的Linux或RTOS(实时操作系统),拥有一个分辨率不高但足够用的LCD屏幕、几个物理按键、一个TF卡槽用于存储,以及最重要的——一块内置电池。我们只是需要“重新定义”它的软件,让它的核心从“记录影像”转变为“运行游戏”。

对于嵌入式开发爱好者和复古游戏迷来说,这个项目极具吸引力。它不仅仅是废物利用,更是一次深入的硬件逆向工程、系统移植和软件定制的综合实践。你需要理解原有设备的启动流程,找到刷入自定义固件的入口,为陌生的硬件编写或移植显示、输入驱动,最后让那些经典的ROM文件在这块小小的屏幕上焕发生机。整个过程充满了挑战,但每一步的成功都带来巨大的成就感。接下来,我将详细拆解我是如何一步步实现这个“变形记”的。

2. 硬件拆解与核心板卡逆向工程

动手改造的第一步,永远是“开膛破肚”。在开始任何软件工作之前,你必须彻底了解你手中的这块硬件。我用到的是一台2018年左右的主流品牌行车记录仪,型号已经模糊,但这并不重要。

2.1 拆机与主要部件识别

小心地撬开行车记录仪的外壳(通常没有螺丝,全是卡扣),内部结构便一览无余。核心是一块主板,上面焊接了主要的芯片。我迅速识别出了以下几个关键部件:

  1. 主控芯片(SoC) :这是整个设备的大脑。我看到的芯片丝印被打磨过一部分,这是厂商防止方案被轻易复制的常见做法。但通过周边电路和内存型号,结合经验,我推测它是一颗基于ARM Cortex-A7架构的廉价SoC,类似全志V3s、瑞芯微RK3066之类的早期产品。这类芯片性能足以流畅运行PS1及以下时代的游戏模拟器。
  2. 内存(RAM) :紧挨着主控的是一颗DDR3内存芯片,容量通常是512MB或1GB。对于复古模拟器来说,512MB已经绰绰有余。
  3. 存储(Flash) :主板上一颗8GB或16GB的eMMC芯片,用于存放原厂固件和录制的视频。这是我们后期需要“攻克”的核心——替换掉里面的系统。
  4. 屏幕接口 :通过一条细长的排线连接到主板。需要记录下排线的引脚数和接口类型(通常是MIPI DSI或RGB接口)。
  5. 按键板 :行车记录仪的按键(如录像、菜单、电源)通过另一条排线或导电橡胶连接到主板。我们需要将这些按键映射为游戏机的方向键和功能键(A/B/X/Y等)。
  6. 摄像头模块 :这个在游戏机项目中用不上了,可以物理断开以省电。
  7. 电池 :通常是一块3.7V的锂聚合物电池,容量在500-1000mAh之间。需要测试其实际容量和健康状况,这决定了游戏机的续航。
  8. TF卡槽 :这是我们的“游戏卡带”插槽,未来所有的游戏ROM都将存放在这里。

注意 :拆机时务必先断开电池!使用塑料撬棒避免划伤外壳和主板。最好用手机对每一步拆解过程、特别是芯片丝印和排线接口进行多角度拍照,这些照片在后续查找资料和接线时至关重要。

2.2. 寻找刷机突破口:UART与测试点

要灌入我们自己的系统,首先得能和设备里的处理器“对话”。最通用、最可靠的方法是找到主板的UART(串口)调试接口。几乎所有嵌入式设备在生产调试阶段都会预留UART引脚。

我使用万用表,在主板边缘寻找疑似测试点(通常是一些排列整齐的、没有焊接元件的金属焊盘)。标准的UART需要三根线:TX(发送)、RX(接收)、GND(地)。通过测量,我找到了一个包含四个焊点的区域。上电后,用万用表电压档测量每个点对GND的电压。一个稳定的3.3V点可能是VCC,一个0V是GND,另外两个在0V和3.3V之间跳变的,很可能就是TX和RX。

我将一个USB转TTL串口模块的GND接主板GND,RX接主板的TX,TX接主板的RX(注意交叉)。然后在电脑上打开串口终端软件(如Putty、MobaXterm),设置常见的波特率(115200是最常见的)。给行车记录仪上电的瞬间,终端里如果出现乱码或启动日志,就说明找对了。调整波特率直到日志清晰可读。这些启动日志是宝藏,它会打印出CPU型号、内存初始化信息、以及最重要的—— uboot的启动命令和参数 。从这里,我确认了SoC的具体型号(例如全志F1C100s),并看到了系统从eMMC启动的完整命令。

3. 固件选型、定制与刷写

有了硬件信息和通信渠道,下一步就是为它选择一个合适的“灵魂”——操作系统和模拟器前端。

3.1 操作系统与模拟器前端的选择

针对这类资源有限的嵌入式ARM设备,有多个成熟的开源选择:

  1. RetroPie / Recalbox :这是树莓派上最流行的复古游戏系统。它们的优势是生态完善,模拟器核心多,前端美观。但它们的系统镜像通常针对树莓派的特定硬件(如博通GPU)做了深度优化,直接移植到其他ARM板子上驱动(尤其是显示和GPU)会非常困难,不适合作为初版选择。
  2. Lakka :它是Libretro核心的官方发行版,本质上是一个极度精简的Linux系统+EmulationStation前端。它的架构更清晰,对非标准硬件的支持相对友好一些,但同样需要自己移植显示和输入驱动。
  3. 自主构建Linux系统 :这是最彻底、也是最灵活的方式。即使用Buildroot或Yocto这类工具,从零开始构建一个最小的Linux系统,然后手动集成SDL2图形库、RetroArch模拟器框架和EmulationStation前端。虽然工作量最大,但可以做到对硬件资源的极致控制,剔除所有不必要的服务,并且能精准地为我们的特定屏幕和按键编写驱动。

考虑到我的行车记录仪SoC比较冷门,社区现成的镜像基本没有。我选择了 第三条路:用Buildroot构建定制系统 。这样做的好处是,我可以从内核配置开始,只启用我需要的驱动(如FrameBuffer驱动、输入子系统驱动),确保系统最小、最快。

3.2 构建定制系统镜像

我的构建环境是一台Ubuntu虚拟机。过程大致如下:

  1. 获取Buildroot :从官网下载最新稳定版。
  2. 配置Target :在 make menuconfig 界面中,选择正确的CPU架构(ARM little endian)、具体型号(如Cortex-A7)、工具链等。在 System configuration 中,设置主机名、root密码等。
  3. 配置内核 :Buildroot可以自动下载和构建Linux内核。关键步骤是获取并配置适合我们SoC的内核源码。幸运的是,许多国产芯片的源码在GitHub上都有爱好者维护的版本。我找到了一个针对全志F1C100s的、已经打好显示和基本外设补丁的内核仓库。
  4. 编写设备树(Device Tree) :这是Linux内核识别硬件的关键。我需要根据我的主板,修改设备树源文件(.dts)。主要工作是:
    • 屏幕参数 :根据屏幕驱动芯片的数据手册(通常需要根据屏幕型号去网上搜索“规格书”),在设备树中正确配置时序参数(如像素时钟、前后肩、分辨率)。
    • 按键映射 :将行车记录仪上的物理按键(通常连接在GPIO上),在设备树中定义为标准键盘事件或GPIO按键。例如,将“录像键”映射为“Enter”,将“菜单键”映射为“Escape”。
  5. 选择软件包 :在Buildroot的包选择中,我勾选了:
    • SDL2 、 SDL2_ttf (图形和字体库)
    • retroarch + 需要的 libretro 核心(如 pcsx-rearmed for PS1, snes9x for SNES, genesis-plus-gx for MD)
    • emulationstation (前端界面)
    • evtest (调试输入设备用)
  6. 编译 :执行 make ,Buildroot会自动下载所有源码、打补丁、配置、编译,最终生成一个完整的系统镜像(通常是一个 sdcard.img 文件),这个过程可能需要数小时。

3.3 刷写系统到设备

生成镜像后,就需要把它写入行车记录仪的存储中,替换原来的系统。这里有几种方法:

  • 方法A:通过TF卡启动(如果支持) :这是最安全的方式。先将镜像写入一张TF卡。然后,我们需要诱使设备从TF卡而不是内置eMMC启动。这通常需要通过UART在uboot阶段中断启动,并手动输入命令 setenv bootcmd “……” 和 saveenv 来修改启动顺序。如果成功,设备就会从TF卡启动我们构建的系统。这相当于给设备装了一个“外置硬盘”,原系统丝毫未动。
  • 方法B:直接刷写eMMC :更彻底,但风险高。在通过TF卡启动我们的系统后,系统已经运行起来。此时,我们可以用 dd 命令,将TF卡上的系统分区,直接克隆到eMMC对应的块设备上(例如 /dev/mmcblk0 )。 操作前必须百分百确认目标设备路径,否则会彻底变砖。

我强烈推荐 先使用方法A 。在TF卡上把系统完全调通,包括显示、声音、按键全部工作正常后,再考虑是否刷入eMMC。我的整个开发调试阶段,都是通过TF卡启动进行的。

4. 驱动适配与输入映射:让硬件“听懂”指令

系统跑起来了,但很可能屏幕是黑的,按键没反应。这是最考验耐心的环节——驱动适配。

4.1 FrameBuffer显示驱动调试

如果屏幕不亮,首先通过UART登录系统,检查FrameBuffer设备是否存在: ls /dev/fb* 。通常会是 /dev/fb0 。

  1. 检查内核日志 : dmesg | grep -i “drm\|fb\|display” ,查看内核是否成功探测到显示控制器和屏幕。
  2. 测试FrameBuffer :如果 /dev/fb0 存在,可以尝试用一个小程序清屏或画图来测试。例如,使用 cat /dev/urandom > /dev/fb0 ,如果屏幕出现随机雪花点,说明FrameBuffer基础功能是通的,问题可能在前端软件的分辨率设置上。
  3. 调整分辨率 :EmulationStation和RetroArch通常需要指定分辨率。如果设备树里设置的分辨率是800x480,但系统报告的不一样,就需要在 /boot 目录下的配置文件中(或者ES的 es_settings.cfg 、RetroArch的 retroarch.cfg 里)强制指定 video_fullscreen_x = “800” 和 video_fullscreen_y = “480” 。

在我的案例中,屏幕点亮了,但颜色严重异常,偏绿或闪烁。这通常是设备树中 display-timings 节点下的像素时钟( clock-frequency )或同步信号极性( vsync-active , hsync-active )设置不对。我对照屏幕规格书和内核启动日志的报错,反复调整这些参数,最终才得到稳定的图像。

4.2 按键与GPIO输入映射

行车记录仪的按键通常直接连接到SoC的GPIO引脚,通过中断或轮询检测电平变化。

  1. 识别GPIO :在设备树中,我根据原理图(如果没有,就用万用表测量按键按下时,哪个GPIO引脚对地短路)将对应的引脚定义为 gpio-keys 。
    &pio {
        game_keys: game_keys {
            pins = “PE0”, “PE1”, “PE2”, “PE3”; // 假设这四个GPIO连接了按键
            function = “gpio_in”;
            bias-pull-up; // 启用内部上拉,按键按下时接地
        };
    };
    
    gpio-keys {
        compatible = “gpio-keys”;
        pinctrl-names = “default”;
        pinctrl-0 = <&game_keys>;
    
        key-a {
            label = “KEY_A”;
            linux,code = <30>; // 对应键盘的 “A” 键
            gpios = <&pio 4 0 GPIO_ACTIVE_LOW>; // PE0
        };
        // … 定义其他按键
    };
    
  2. 系统内测试 :系统启动后,使用 evtest 工具选择 /dev/input/event0 (或其他event设备),然后按下物理按键,观察终端是否输出对应的键值。这是验证按键驱动是否生效的黄金标准。
  3. 在EmulationStation中配置 :EmulationStation首次运行或进入其输入配置模式时,会提示你按下各个功能对应的按键。此时,按照提示按下行车记录仪上的物理按键即可完成映射。映射文件会保存在 /home/root/.emulationstation/es_input.cfg 中。
  4. 在RetroArch中配置 :EmulationStation负责前端导航,游戏内的控制则由RetroArch管理。我们需要在RetroArch的输入设置里,将“端口1控制”的设备类型设为“RetroPad”,然后将其各个功能(上、下、左、右、A、B、X、Y、L、R、Start、Select)映射到对应的键盘键值(也就是我们在设备树里定义的 linux,code )。这样,一套物理按键就能同时控制前端和游戏。

5. 系统优化、美化与实战测试

当显示和输入都正常工作后,一个可玩的游戏机雏形就诞生了。但要让体验更好,还需要进行一系列优化。

5.1 性能调优与功耗管理

复古模拟器对CPU要求不高,但优化能提升续航和稳定性。

  1. CPU调速器 :默认的 ondemand 或 powersave 调速器可能反应迟缓。对于游戏场景,我将其设置为 performance ,让CPU始终以最高频率运行,减少模拟音频或复杂图形时的卡顿。命令: echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 。可以将此命令写入启动脚本。
  2. 关闭不需要的服务 :Buildroot系统本身很干净,但还是要检查一下是否有多余的守护进程(如网络管理、蓝牙等)。用 ps aux 查看,并用 systemctl disable 关闭它们。
  3. 电池电量显示 :行车记录仪的电池电量检测通常是通过ADC读取的。需要在设备树中启用ADC和电池监测驱动,然后系统会在 /sys/class/power_supply/ 下生成一个节点(如 battery )。EmulationStation有插件可以显示电池图标,但这需要额外的开发。一个简单的替代方案是写一个脚本,定期读取电量文件并生成一个简单的文本提示。
  4. 自动关机 :为了防止电池过放,可以设置一个低电量自动关机的脚本,或者更简单地,设置一个无操作自动关机定时器( systemctl enable systemd-sleep 相关配置)。

5.2 前端美化与游戏列表生成

默认的EmulationStation主题可能不太好看。我们可以从网上下载其他主题包(如 es-theme-carbon ),解压到 /etc/emulationstation/themes/ 目录下,然后在ES的设置中选择新主题。

更大的工作量是游戏列表管理。将游戏ROM( .sfc , .md , .psx 等格式)放入TF卡对应的 roms 目录(如 /roms/snes/ )后,EmulationStation启动时会自动扫描并生成列表。但它显示的是文件名。为了有漂亮的封面和游戏描述,我们需要使用 Skyscraper 或 EmulationStation 自带的scraper工具 。

由于我们的设备很可能没有网络,最佳实践是在PC上完成这个“刮削”工作:

  1. 在PC上安装Skyscraper。
  2. 将TF卡通过读卡器连接PC,把ROM文件夹复制到PC。
  3. 在PC上运行Skyscraper,指定平台和ROM路径,它会从ScreenScraper.fr等网站下载游戏元数据、封面图、视频预览等。
  4. 将处理好的 roms 目录和生成的 gamelist.xml 文件拷贝回TF卡。 这样,在游戏机上就能看到带封面的精美游戏列表了。

5.3 多平台模拟器实测与兼容性

我测试了多个平台的游戏,以下是我的实测总结:

模拟器核心 (Libretro) 对应平台 性能表现 (Cortex-A7 @ 1GHz) 关键设置建议
Genesis Plus GX Sega Mega Drive/Genesis 完美全速 默认即可,可开启整数倍缩放保持点对点像素。
Snes9x (2010) Super Nintendo 绝大多数游戏全速 对《星际火狐》等搭载特殊芯片的游戏可能略有掉帧,可尝试切换到更快的“Snes9x Next”核心。
PCSX-ReARMed Sony PlayStation 1 大部分2D游戏和早期3D游戏全速 必须启用动态重编译器(Dynarec)。对于《最终幻想9》等复杂3D场景,需要适度降低分辨率(如从640x480降到320x240)或关闭一些增强效果(如纹理过滤)。
MAME 2003-Plus 街机 (Arcade) 取决于游戏 对NeoGeo、CPS1/2基板游戏支持很好。需要精确的ROMset版本,建议使用FBA核心作为补充。
Gambatte Nintendo Game Boy (Color) 完美全速 可开启LCD网格着色器,获得更接近原版掌机的视觉效果。

实测中的关键技巧 :在RetroArch的快捷菜单(游戏中按“热键+X”或类似组合)里, Latency (延迟)设置中的 Run-Ahead 功能可以大幅降低输入延迟,对格斗、动作游戏体验提升巨大。但会轻微增加CPU负担,在性能紧张的PS1模拟中需酌情开启。

6. 外壳改造与最终装配

软件和硬件调试完毕,最后一步是让它看起来和用起来都像一台真正的掌机。

  1. 外壳修整 :行车记录仪的外壳有摄像头孔和多余的按键孔。我用AB补土或热熔胶将这些孔洞填平,干透后打磨平整。对于屏幕,可以裁剪一块手机贴膜或亚克力板,用无影胶贴合,作为保护盖板。
  2. 按键重塑 :原机的按键布局肯定不适合打游戏。我购买了现成的游戏机导电胶按键(淘宝上几块钱一套),然后在外壳上重新开孔。开孔位置需要精心设计,以符合人体工学。使用手电钻和小锉刀慢慢加工。将新的导电胶按键碗对准主板飞线焊接的触点(或使用原来的按键板改造)。
  3. 音频增强 :原机喇叭通常音质很差。我拆了一个旧蓝牙音箱里的微型扬声器替换上去,音质立竿见影。记得在RetroArch的音频设置里,将输出改为 alsa ,并调大音量增益。
  4. 电池考量 :原装电池可能老化。我测量了游戏时的整机功耗(约500mA),然后选择了一块尺寸合适、容量更大的3.7V锂电池(约2000mAh),并更换了对应的保护板。续航从原来的1小时提升到了4小时以上。
  5. 最终组装 :将所有部件——主板、新电池、扬声器、按键板——用螺丝或胶固定好。确保所有排线插紧,没有短路风险。合上外壳,一台独一无二的、由行车记录仪改造的复古游戏掌机就诞生了。

这个项目最迷人的地方在于,它迫使你去深入理解从硬件信号到软件抽象的完整链条。每一次屏幕点亮、每一次按键响应,都是对底层原理的一次验证。当你最终握着这台自己亲手改造的设备,玩着《魂斗罗》或《最终幻想7》时,那种成就感远超购买任何一台现成的商品。它不再是一个行车记录仪,也不仅仅是一台游戏机,它是一个凝结了探索、学习和创造过程的实体作品。

更多推荐