基于安信可Ai-M61开发板的自制U盘红白机教程
本文转自立创开源广场,原作者「拿了桔子跑」
原文地址:https://oshwhub.com/article/article_vcmwvopo
编者按:
手里有一块吃灰的 Ai-M61 或 Ai-M62,还能拿它做什么?
立创开源广场上有个作品给了个精彩的答案:把它做成一个打火机大小的 U 盘,插上电脑,系统认成「带麦克风的摄像头」,相机软件里直接出红白机画面。
项目叫 USB-NES。一颗 RISC-V 在片上跑 InfoNES,画面走 UVC、声音走 UAC、手柄走 HID,一根 USB 线把三件事一起做了,全程不需要板子带屏。
原理并不复杂:模拟器本来就在一帧一帧算画面,只要把算出来的画面编码成 MJPEG、当成摄像头推出去,任何带屏的设备都能当它的显示器。
「必须带屏」这条约束一去,Ai-M61 / M62 这类小板的可玩性一下就宽了。
我们觉得这个思路值得给手上正好有块吃灰板子的人看看,所以把原作者的文章整理出来。
下文为原作者正文,我们只做排版整理,技术细节与结论保留作者原意。
家人们,有没有手里吃灰的Ai-M61 / Ai-M62开发板?这些板子其实完全够跑 NES 红白机,但之前一直没个像样的玩法。
说个我自己的经历:早先用小安派 S1自己搓了个模拟器玩小霸王(参考这篇),结果是能玩,但有两个硬伤——一是那个模拟器只支持 Mapper0 格式的 NES,像魂斗罗这种非 Mapper0 的游戏根本跑不起来;二是 S1 靠触摸屏操作,手感一言难尽。更麻烦的是,那版固件必须小安派 S1 才能跑,换块板子就歇菜。
后来学 USB 的时候灵光一现:既然画面是模拟器自己算出来的,干嘛非要板子带屏幕?让电脑把模拟器画面当「摄像头」收进来不就完了——于是 UVC 视频 + UAC 音频 + HID 手柄三根线合一的复合 USB 设备就出来了,而且任何带 Ai-M61/Ai-M62 的板子都能跑。当前这版做得只有打火机大小,直接挂钥匙扣上,小巧方便。
这次咱们玩的硬核货——USB-NES:一颗 RISC-V 片上跑 InfoNES(支持多 Mapper,魂斗罗也能玩),插上 USB 电脑认成「带麦克风的摄像头」,视频、声音、手柄一根线全包,换游戏不用重编固件。妥妥的吃灰板子复活神器~
| 说明:本项目主体是 BL616/BL618 复合 USB 设备(UVC 视频 + UAC 音频 + HID 手柄 + 片上 InfoNES)。下面要讲的 ESP32 小手柄只是其中一种无线控制方式,手机、电脑照样能连。 |
01先上成品展示!
整机就是个打火机大小的 USB 小 Dongle,挂钥匙扣上都行。插上电脑,Windows 设备管理器里会依次冒出「摄像头」「麦克风」「HID 游戏设备」三类。

外壳 3D 渲染(闭合形态):打火机大小,一头 USB 接电脑、一头 TTL 串口,顶上两颗实体按键
Windows 设备管理器:「照相机」和「声音输入」里同时冒出 BL6x8_UVC_UAC_DEMO——一个设备被认成两类

USB Device Tree Viewer 再确认:同一个设备描述符里挂着 Camera, Audio, HID 三接口,标准的 USB 复合设备
02实物展示
设计再漂亮,也得看实机能不能跑。下面是通电、连电脑、出画面的实机照片——重点是这玩意儿只有打火机大。
外壳 3D 渲染(打开视图):迷你 PCB + 双 Type-C 座,Ai-M61/M62 模组焊在中央

双 Type-C 特写:一头 USB(复合设备接电脑),一头 TTL(串口烧录/日志),烧完游戏拔掉 TTL 线就能挂着当 U 盘红白机

实机效果:打开 Windows 自带「相机」,UVC 收到的就是 NES 画面(坦克大战),零驱动、零插件

上电进中文游戏菜单:2048、超级玛丽、魂斗罗、马戏团、炸弹人、坦克大战、公路追逐赛、双截龙……方向键移光标、A 进入,换游戏不用重编固件
03项目卡片与硬件清单
| 项目 | 说明 |
| 核心大脑 | 安信可 Ai-M61 / Ai-M62 / BL616 / BL618 模组(博流 RISC-V,320MHz,4MB PSRAM)——手上有这些板子的都能跑 |
| 体积 | 打火机大小,可直接挂钥匙扣,小巧便携 |
| 屏幕依赖 | 零屏幕 ——画面走 UVC 让电脑/手机当「摄像头」显示,板子本身不用带屏 |
| 交互方式 | 有线 USB HID(PC 网页/小程序转发)+ 无线 UDP(板子开 SoftAP 热点,手机/电脑/ESP32 连上来玩) |
| 视频输出 | UVC 摄像头,硬件 MJPEG 编码,默认 512×480、15fps(实测编码 19fps) |
| 音频输出 | UAC 麦克风,NES APU 5 路波形混音 + 去直流,44.1kHz / 立体声 / 16-bit |
| 手柄通道 | HID(有线)+ 自定义 UDP(无线),最长支持 2 人同屏 |
| 模拟器 | 片上 InfoNES(6502 + PPU + APU),支持多 Mapper(不像早期 S1 那版只认 Mapper0),魂斗罗也能玩 |
| 内置游戏 | 9 款经典(超级玛丽、魂斗罗、坦克大战、双截龙……) |
| 换游戏方式 | flash_rom.py 一条命令写入,免重编固件 |
| 固件分发 | 固件 + 全部游戏拼成单文件合并镜像,一键烧录 |
| 上手难度 | (会编译、会烧录、会写一条命令就行) |
硬件清单
| 部件 | 具体型号/规格 | 说明/来源 |
| 主控 | Ai-M61 / Ai-M62 / BL616 / BL618(博流 RISC-V 320MHz,4MB PSRAM) | 安信可模组,吃灰板子也能用 |
| 体积 | 打火机大小,可挂钥匙扣 | 迷你 PCB,无屏幕 |
| 视频 | 硬件 MJPEG 编码器(RGB565→YUYV 软件转换) | 片上外设,UVC 输出 |
| 音频 | NES APU 5 路混音 + 去直流 | 经 UAC 输出 44.1k 立体声 |
| 手柄 | 板载按键 + USB HID + 无线 UDP | 有线/无线双模,最长 2 人 |
| 存储 | 板载 Flash(固件 + ROM 分区) | ROM 走独立目录区 + 数据区 |
| 接口 | USB 2.0(DP/DN) | Type-C 或 Micro-USB,供电 + 复合设备 |
| 上位机 | PC 网页nes_pad_webhid.html/ 脚本nes_pad_sender.py | 有线转发手柄 |
| 无线端 | 手机 / 电脑 / ESP32 小手柄 | 连板子 SoftAPBL616_NES发 UDP |
04固件设计:一根 USB 线,三个设备
为什么用 UVC 而不是板子带屏?早期在小安派 S1 上玩,板子必须带屏幕才能看到画面,硬件门槛高、还得是特定板子。后来想到:模拟器画面本来就是芯片一帧帧算出来的,只要把它编码成 MJPEG 走 UVC,电脑/手机的相机软件就能直接当「摄像头」显示——板子自己完全不用带屏,任何 Ai-M61/M62 小板都能跑。这步直接把「必须有屏幕」的硬约束拿掉了,也是这个项目能「让吃灰板子玩起来」的关键。
核心思路是把 BL616/BL618 做成一个USB 复合设备(bDeviceClass=0xEFIAD 复合),一根 USB 线同时暴露三个接口:
·UVC(视频):片上 InfoNES 把 NES 画面渲染成 RGB565,软件转成 YUYV,再交给硬件 MJPEG 编码器压成视频流。电脑打开相机软件就能看,不用装任何驱动。
·UAC(音频):NES APU 的五路波形(2× 脉冲、三角波、噪声、DPCM)在片上混音,做过去直流处理,经 UAC 输出 44.1kHz 立体声。电脑录音软件能直接收到游戏原声。
·HID(手柄):板载按键通过 USB HID 回传,PC 网页/小程序读到来转发给模拟器。

不用画架构图,直接上真实枚举证据——USB Tree Viewer 展开看到同一个设备下挂三个子设备:① UVC 视频设备(Camera class)② UAC 音频设备(AudioEndpoint)③ HID 设备(标准游戏手柄)。VID/PID = ABCD:1234,一根 USB 线,三个设备
视频做了BT.601 studio range + 2× 放大的色彩处理,高对比边缘没有红绿鬼影(这点是踩过坑修好的,见后面「踩坑总结」)。模拟器用InfoNES,支持多 Mapper,非 Mapper0 的游戏(如魂斗罗)也能跑——这比早期 S1 那版只认 Mapper0 强太多。
05操控方式:有线 + 无线,最长 2 人
早期 S1 靠触摸屏操作,手感一言难尽;这版回归实体操控——有线 HID + 无线 UDP,手感正常。怎么玩?两种。
A. 有线(零安装):PC 接上真手柄,打开nes_pad_webhid.html网页(WebHID,浏览器直连,不用装驱动),按键一键转发给板子。网页里还能直接预览 UVC 画面和音频——左边选设备,右边出游戏:

nes_pad_webhid.html:网页读 UVC+UAC 直接出画面(坦克大战标题),下方是 NES 风格虚拟手柄,键盘 WASD/J/K 也能玩
B. 无线:板子自己开一个 WiFi 热点BL616_NES,手机、电脑、甚至一块 ESP32 小手柄连上来,发 4 字节 UDP 到192.168.4.1:5000,源端口 5001/5002区分 PAD1 / PAD2,于是能 2 人同屏。

PC 端 UDP 调试工具(连 BL616_NES 热点即用):WASD + A/B/Sel/Sta 点按即发,还有「自动演示」一键跑序列;ESP32 小手柄发的也是同一套 4 字节报文
06烧录与使用
·编译固件:make CHIP=bl616 BOARD=bl616dk
·写游戏(免重编):python tools/flash_rom.py 你的rom.nes一条命令把 ROM 写进 Flash 分区
·拼合并镜像:python tools/make_merged_firmware.py把固件 + 全部游戏拼成单文件
·一键烧录:BLFlashCommand.exe --interface=uart --baudrate=2000000 --port=COMx --chipname=bl616 --cpu_id=ap --config=flash_prog_cfg.ini
·上电:插 USB,电脑识别成摄像头+麦克风,打开相机软件即出画面,上电即进中文游戏菜单
07核心代码:输入源统一
最有意思的一处设计——有线 HID 和无线 UDP 被统一成一个输入源,模拟器核心一行都不用改:
// nes/infones_port.c(节选) // 新增的输入源(无线 UDP)只改这一处,InfoNES 核心零改动 uint8_t pad1_current(void) { return pad_state // 有线 HID 写入的按键 | pad_udp_get_state(0); // 无线 PAD1(UDP server 收到的状态) }
无线端的按键映射也很直白,6 个物理键一一对应「上下左右 + A + B」,全部单键直出:
# nes_pad_udp.py(节选,ESP32 无线手柄端) BUTTON_MAP = ( ("up", BIT_UP), ("dn", BIT_DOWN), ("lt", BIT_LEFT), ("rt", BIT_RIGHT), ("a", BIT_A), ("b", BIT_B), ) # Select / Start 协议里有、物理上没有,用长按补: # b 长按松手 -> Select; a+b 同按 -> Start; b 长按 2s -> 退出
08实测效果
· 插上电脑,设备管理器同时出现摄像头 + 麦克风 + HID 三类设备
· 打开相机软件出 512×480 魂斗罗标题,实测编码 19fps(超出协议声明的 15fps)
· 录音软件收到 NES 五声道 BGM,去直流后不刺耳
· 上电进中文游戏菜单,9 款 ROM 方向键导航、A 进入
· 无线:ESP32 小手柄连BL616_NES热点,4 字节 UDP 操控,PAD1/PAD2 双人
· 换游戏:flash_rom.py一条命令,不用重编固件
实测进行中:坦克大战(非 Mapper0 之外的经典都能跑,魂斗罗同理),WebHID 网页画面 + 虚拟手柄操控,延迟肉眼无感。
09踩坑总结
坑1:画面边缘红绿鬼影
一开始 NES 画面放大后,高对比边缘出现红/绿拖影(chroma ghosting)。根因是色彩范围用了 PC 的 full range + 简单的 1× 复制。改法:用BT.601 studio range + 2× 放大,鬼影消失。现在可放心当卖点。
坑2:音频有直流偏移、低频嗡嗡声
NES APU 混音直出时带直流分量,喇叭会有「噗噗」底噪。在混音后加了一级去直流(高通/减均值),44.1k 立体声输出干净了。
10升级思路|玩出更多花样
·更多 ROM:Flash 分区还有余量,继续塞经典;
·实体手柄:使用 WB2 或者 M61做成真正能握的无线手柄;
·音频升级:APU 接板载 DAC 直推小喇叭,脱离电脑也能外放;
最后说两句
USB-NES 最爽的点在于:它把你手里吃灰的 Ai-M61/M62 板子变成了能插电脑就玩的红白机——不用屏幕、不用小安派 S1、魂斗罗也能跑,打火机大小挂钥匙扣上。从「编译固件」到「写游戏进 Flash」再到「插上电脑就能玩」全链路可控。一根 USB 线,电脑认成摄像头,里面却在跑魂斗罗——这种「骗过操作系统」的硬核浪漫,比刷一百个短视频都强。
如果你手上有块吃灰的 Ai-M61/M62 想让它复活,欢迎参考这个项目。有任何问题评论区留言,一起交流~
