0%

🎮 ESP32 小喵掌机 NES 模拟器:SD卡版 + WiFi文件管理

把小喵掌机(学而思 ESP32 编程掌机)改造成 NES 红白机模拟器,支持 SD 卡读取 ROMWiFi Web 文件管理菜单式双槽位存档/读档,还能在浏览器里上传游戏!

📦 项目地址:github.com/noahgeek/nofrendo-xiaomiao

ESP32小喵掌机NES模拟器运行效果

🎯 项目简介

本项目基于 arduino-nofrendo 改造,适配学而思 ESP32 小喵掌机 ESP32 + ST7735 160×128 屏幕,围绕 SPI2 总线冲突修复、内存中转存档等关键技术难题,实现了完整的 NES 模拟体验。

✨ 核心特性

  • 🖥️ ST7735 160×128 显示,NES 256×240 缩小适配全屏
  • 💾 SD 卡读取 ROM,从 /rom/ 目录加载 .nes 文件,开机选档菜单
  • 📀 菜单式双槽位存档/读档,弹出菜单含存档时间,上下选槽位 A 确认
  • 📡 WiFi Web 文件管理,浏览器上传 ROM、下载存档、删除/改名文件
  • 🎮 掌机 6 键 + 串口键盘备用控制
  • 🔊 蜂鸣器 PWM 音频(可开关)

🔧 硬件接线(小喵掌机)

TFT 引脚ESP32 GPIO说明
VCC3V3电源
GNDGND接地
SCKGPIO 18SPI SCLK(与 SD 卡共享)
SDA(MOSI)GPIO 23SPI MOSI(与 SD 卡共享)
CSGPIO 5片选
DCGPIO 4数据/命令
RESGPIO 19与 SD 卡 MISO 共享
BLKGPIO 5背光

TFT 与 SD 卡共用 SPI2 总线(GPIO18/23/19),通过各自 CS 分时复用。

💡 技术亮点

1. SPI2 总线冲突修复(关键)

TFT 与 SD 卡共享 SPI2 总线。旧版菜单式存读档崩溃由两层因素叠加导致:

  1. nofrendo_pause_timer() 只停止定时器递增,但 nes_emulate() 主循环仍可能在帧需渲染时调 vid_flush 继续写屏(SPI2);
  2. sdTask 在同一窗口内操作 SD 卡(SPI2 DMA)→ 两条路径争抢 SPI2 → ESP32 Guru Meditation 崩溃。

修复方案:新增 volatile bool g_emulation_suspended 标志,pause 时置 true 跳过渲染循环,让 SPI2 空闲给 sdTask。

2. 内存中转存档:零竞态条件

NES 状态保存/恢复在定时器回调内同步完成(纯内存操作,约 31KB blob),SD 卡写入在独立任务中异步完成。操作 SD 卡前通过 g_emulation_suspended 挂起 nes_emulate(),确保 displayTask 不再争抢 SPI2。

3. 双槽位存档(取代 .bak 备份)

采用 sa1 / sa2 两个独立槽位,存档菜单显示各自时间戳(YYYY-MM-DD HH:MM),由 SNTP 同步后格式化。历史保护由双槽位本身提供,不再需要额外的备份文件。

4. GPIO19 复用

GPIO19 同时是 TFT RES 和 SD MISO。解决方案:TFT 使用软件复位命令(RST = -1),不占用 GPIO19;GFX bus 的 MISO 设为 19;display_begin() 后再调一次 sdSpi.begin() 确保 SPI 路由正确。

5. WiFi 内存管理

WiFi 仅在选档菜单期间运行,进入 NES 模拟器前停止 Web 服务器并释放内存,避免 WiFi 占用过多 RAM 导致游戏崩溃。进游戏后 WiFi 进入省电模式减少后台中断对 SD 卡 SPI 的干扰。

🎮 按键映射

掌机按键NES 功能
方向键方向键
A (GPIO34)A 键
B (GPIO12)B 键
上+下+BSELECT
上+下+ASTART
左+右+B💾 弹出存档菜单(2 槽位)
左+右+A📂 弹出读档菜单(2 槽位)
左+上+右+A🔊 蜂鸣器开关

📡 WiFi 文件管理

选档菜单期间,浏览器访问屏幕显示的 IP 地址即可:

  • 浏览 /rom/save 目录
  • 上传 ROM 文件到 SD 卡
  • 下载存档文件(.sa1 / .sa2)到电脑
  • 删除/改名文件

小喵掌机WiFi文件管理

小喵掌机WiFi文件管理界面

🚀 快速开始

  1. SD 卡格式化为 FAT32,根目录建 rom 文件夹,放入 .nes ROM 文件
  2. Arduino IDE 安装 Arduino_GFX 库(不要装 nofrendo 库,项目自带源码)
  3. 开发板选 ESP32 Dev Module,分区方案 Default 4MB with SPIFFS,PSRAM Enabled
  4. ESP32 开发板库版本 2.0.9(其他版本可能无法点亮屏幕)
  5. 编译烧录 → 上电 → 连接 WiFi → 浏览器上传 ROM → 选游戏开玩!

⚠️ 踩过的坑

  • 不要装 Arduino IDE 的 nofrendo 库:项目自带 src/ 目录包含完整源码,重复会冲突
  • TFT 与 SD 卡共用 SPI2 总线:已通过 g_emulation_suspended 互斥机制修复,选档/存读档期间自动暂停 NES 渲染
  • WiFi 在游戏内不可用:非 bug,进游戏后停止 Web 服务器释放内存,按 B 退回选档菜单即可恢复
  • 无 SD 卡也能玩:固件自动回退到 SPIFFS 分区 ROM(需先烧录)

📚 致谢

欢迎到 GitHub 给项目点个 ⭐!有问题或者改进建议都可以提 Issue~